From: Tom Hromatka Date: Tue, 7 Apr 2020 13:58:19 +0000 (-0600) Subject: git: folder re-organization X-Git-Tag: v2.0.3~11^2^2~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbbc5b2bf3b17bb5b046247aca650b1230cd5e35;p=thirdparty%2Flibcgroup.git git: folder re-organization In preparation of moving the tests to their own git repo, this commit deletes every file/folder other than the test folder. Signed-off-by: Tom Hromatka --- diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6d7c3d75..00000000 --- a/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -patches/* -*.o -*.lo -*.la -*.gcda -*.gcno -*.gcov -stamp-* -*.cache -.deps/ -.libs/ -*~ -Makefile -Makefile.in -config.guess -config.h -config.h.in -config.log -config.status -config.sub -configure -depcomp -libtool -ltmain.sh -m4 -missing -install-sh -aclocal.m4 -ylwrap -*.pc -googletest/ -googletest/* diff --git a/.gitmodules b/.gitmodules index bfb1b5aa..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +0,0 @@ -[submodule "googletest"] - path = googletest - url = https://github.com/google/googletest.git - fetchRecurseSubmodules = true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 72e202b1..00000000 --- a/.travis.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Travis CI configuration for libcgroup -# -# Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. -# Author: Tom Hromatka -# - -# -# This library is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License as -# published by the Free Software Foundation. -# -# This library is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this library; if not, see . -# - -dist: bionic -sudo: false - -git: - submodules: false - -notifications: - email: - on_success: always - on_failure: always - -language: c -compiler: - - gcc - -addons: - apt: - packages: - - lcov - - lxc - - lxd - -before_install: - # see https://github.com/eddyxu/cpp-coveralls - - pip install --user cpp-coveralls - -# perform the build and fail immediately on error -install: - - ./bootstrap.sh - - make clean - # enable code coverage - - CFLAGS="$CFLAGS -g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-code-coverage - - make - -script: - - make check - -after_failure: - - cat tests/ftests/test-suite.log - -after_success: - - coveralls --exclude tests --exclude googletest --exclude samples --gcov-options '\-lp' diff --git a/COPYING b/COPYING deleted file mode 100644 index 2d2d780e..00000000 --- a/COPYING +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should -have at least the "copyright" line and a pointer to where the full -notice is found. - - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/INSTALL b/INSTALL deleted file mode 100644 index d3c5b40a..00000000 --- a/INSTALL +++ /dev/null @@ -1,237 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006, 2007 Free Software Foundation, Inc. - -This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. - -Basic Installation -================== - -Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is -disabled by default to prevent problems with accidental use of stale -cache files. - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. - -The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. - - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package. - - 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - - 6. Often, you can also type `make uninstall' to remove the installed - files again. - -Compilers and Options -===================== - -Some systems require unusual options for compilation or linking that the -`configure' script does not know about. Run `./configure --help' for -details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c99 CFLAGS=-g LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - -You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. - - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. - -Installation Names -================== - -By default, `make install' installs the package's commands under -`/usr/local/bin', include files under `/usr/local/include', etc. You -can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX'. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -pass the option `--exec-prefix=PREFIX' to `configure', the package uses -PREFIX as the prefix for installing programs and libraries. -Documentation and other data files still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=DIR' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - -Optional Features -================= - -Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - -Specifying the System Type -========================== - -There may be some features `configure' cannot figure out automatically, -but needs to determine by the type of machine the package will run on. -Usually, assuming the package is built to be run on the _same_ -architectures, `configure' can figure that out, but if it prints a -message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the option `--target=TYPE' to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - -Sharing Defaults -================ - -If you want to set default values for `configure' scripts to share, you -can create a site shell script called `config.site' that gives default -values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Defining Variables -================== - -Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). - -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: - - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash - -`configure' Invocation -====================== - -`configure' recognizes the following options to control how it operates. - -`--help' -`-h' - Print a summary of the options to `configure', and exit. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. - diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index e87ec8af..00000000 --- a/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -AUTOMAKE_OPTIONS = foreign -ACLOCAL_AMFLAGS= -I m4 -SUBDIRS = dist doc include samples scripts src tests - -EXTRA_DIST = README_daemon libcgroup.doxyfile README_systemd - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libcgroup.pc diff --git a/README b/README deleted file mode 100644 index 54e0f7bb..00000000 --- a/README +++ /dev/null @@ -1,183 +0,0 @@ -Design -======== - -After cgroup system has taken shape, its time to have some basic tools -in user space which can enable a user to use the resource management -functionality effictively. - -One of the needed functionality is rule based placement of a task. In general, -there can be either uid or gid or exec based rules. Admin/root will -control/enforce uid/gid based rules and exec based rules can be defined by -user in a config file residing in user's home dir and fully controlled by user. - -uid/gid based rules will be defined in /etc/cgrules.conf config file and -this file will be managed by root. - -Basic idea is that to begin with provide facility to implement rules -based on uid and gid. So a hierarchy might look like as follows. - - /mnt/cgroup - | | - gid1 gid2 - | | - uid1 uid2 - | | - proj1 proj2 - - -Admin will write rules to control the resources among users. Then users -can manage their own cgroup at their own (proj1 and proj2) and control -the resources as they want. - -Following are the few methods using which tasks can be placed in right -cgroups. - -- Use pam_cgroup PAM plugin which will make sure users are placed in right - cgroup at login time and any tasks launch after login, will continue to run - in user's cgroup. - -- Use command line tool "cgexec" to launch the task in right cgroup. - -- Modify the program and use libcgroup provided APIs for placing a task - in right cgroup before doing exec(). - -- Use "cgclassify" tool to classify a already running task. - -- May be, a user space daemon can also be implemented which will listen to - kernel events and place the task in right group based on the rules. - This method involves few concerns. - - - Reliability of netlink socket. Messages can be dropped. - - Change the netlink with a cgroup controller which exports the - events. - - - Delay incurred since the event took place and task was actually placed - in right cgroup. - - - daemon will interfere with container's tasks which is not desired. - -HOWTO -===== - -Section 1: ----------- -To use "cgexec" to place the task in right cgroup. - -- make cgexec -- Run a task using cgexec. Following is the cgexec syntax. - - cgexec [-g :] command [arguments] - - Note: Cgroup controllers and path are optional. If user does not know the - right cgroup, cgexec will automatically place the task in right - cgroup based on /etc/cgrules.conf - -Example: - cgexec -g *:test1 ls - cgexec -g cpu,memory:test1 ls -l - cgexec -g cpu,memory:test1 -g swap:test2 ls -l - -Section 2 ---------- -To use "cgclassify" to place task in right cgroup. - -- make cgclassify -- Pick a task's pid to be classified, and run - cgclassify - -Example: --------- - cgclassify 2140 4325 - - Note: After classification check out whether tasks 2140 and 4325 - are in the right cgroup or not (Based on rules in /etc/cgrules.conf) - -Section 3: ----------- -To use a pam plugin which will automatically place the task in right -cgroup upon login. - -- Build pam_cgroup.so - make pam_cgroup.so -- Copy pam_cgroup.so to /lib/security/ -- Edit /etc/pam.d/su to make use of pam_cgroup.so session module upon - execution of su. - -example: - Add following line at the end of /etc/pam.d/su file - -session optional pam_cgroup.so - -- Now launch a shell for a user "xyz" using su and the resulting shell - should be running in the cgroup designated for the user as specified - by cgrules.conf - - ex. "su test1" - -Try similar things with other services like sshd. - -Note: pam_cgroup.so moves the service providing process in the right cgroup - and not the process which will be launched later. Due to parent child - relationship, yet to be forked/execed process will launch in right - group. - -Ex. Lets say user root does "su test1". In this case process "su" is the - one providing service (launching a shell) for user "test1". pam_cgroup.so - will move process "su" to the user "test1"'s cgroup (Decided by the uid - and gid of "test1"). Now once su forks/execs a shell for user test1, - final shell is effectively running in the cgroup it should have been - running based on /etc/cgrules.conf for user test1. - - -Section 4: ----------- -To use cgrulesengd which will move a task to right cgroup based on -rules in /etc/cgrules.conf do following. - -- build and install latest libcgroup.so -- build cgrulesengd - make cgrulesengd -- specify some uid/gid based rules in /etc/cgrules.conf -- Mount some controllers and create an hierarchy of cgroups (matching - your rules). -- Run cgrulesengd. - - ./cgrulesengd -- Launch some task or login as a user to the sytem. Daemon should automatically - place the task in right cgroup. - -FAQ -=== -Q. Why admin should not control "exec" based rules. -A. Unix file system provides access control only based on uid/gid. So - even if admin starts putting tasks based on uid/gid, it can't enforce - it. For example, consider following scenario. - - Lets say an admin creates following cgroup hierarchy. - - /container - | | - database browser - | | | | - user1 user2 user1 user2 - - Now admin wants to run all the database jobs under /container/database/ - and all the firefox jobs under /container/browser/. Based on which user - launched it, jobs should go in either user1 or user2 dir. - - Now assume that database subdir has to more cpu resources as compared to - browser subdir. Then a user, say user2, can always move his browser job - also to /container/database/user2 dir to get more cpu resources and - admin will not be able to control that. - - [Note: user2 will control what tasks can be added in /container/database/user2 - and will contol what further subdirs can be created under user2 dir. Root - should not restrict the control to root only for practical purposes. Its - something like that till /container/databse, admin controls the resources - and below that how resources are further subdivided among various projects - should be controlled by respective user]. - -In the light of above, it seems to make more sense that admin should enforce -rules only based on uid and gid. Probably later we can have a per user exec -based rules config file (~/.cgrules.conf), which can be parsed by cgrulesd -and then jobs launched by user will be placed in right cgroup based on -combination of rules in /etc/cgrules.conf and ~/cgrules.conf. diff --git a/README.md b/README.md deleted file mode 100644 index 06770378..00000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -[![Build Status](https://img.shields.io/travis/libcgroup/libcgroup/master.svg)](https://travis-ci.org/libcgroup/libcgroup) -[![Coverage Status](https://img.shields.io/coveralls/github/libcgroup/libcgroup/master.svg)](https://coveralls.io/github/libcgroup/libcgroup?branch=master) - -The entire libcgroup README is available [here](README). diff --git a/README_daemon b/README_daemon deleted file mode 100644 index 25f0d550..00000000 --- a/README_daemon +++ /dev/null @@ -1,182 +0,0 @@ -DESCRIPTION -=========== -The CGroup Rules Engine Daemon is a tool that will automatically place tasks -into the correct cgroup based on UID/GID events from the kernel. It will not -automatically classify tasks that are already running, but it will classify -any new tasks, and any tasks which change their UID/GID. Note that we use -the euid and egid, not the ruid and rgid. - -Unlike other tools, cgrulesengd caches the rules configuration in a data -structure (it's actually just a FIFO linked list) so that it doesn't need to -parse the configuration file more than once. This should be much faster than -parsing the rules for each UID/GID event. Eventually, this caching logic -should be part of libcgroup, so that any other program can take advantage of it -(and so that all programs are using the same table). The configuration can -be reloaded without stopping the daemon (more information below). - -WHY A DAEMON? -============= -A daemon is easy to use, and allows an administrator to ensure that all tasks -are classified into the correct cgroups without constantly monitoring the -system. The daemon is transparent to the users, and does not require any -modifications to existing userspace programs. Finally, the daemon can be -started and stopped at any time, including at boot time with other services. -Thus, sytem administrators can decide not to use the daemon if they choose. - -Most importantly, some programs create new users and/or run scripts, -threads, etc. as those users using suexec(). This call does not go through -PAM, so these scripts would continue running in the same cgroup as the parent -program. This behavior is likely not ideal, and the daemon would solve this -problem. - -Apache does this. Apache creates a user called 'apache' and uses setuid() to -launch tasks as that user. This does not go through PAM, so without a daemon, -these tasks would continue to run in the 'root' cgroup rather than in the -'apache' or 'webserver' cgroup. The daemon fixes this problem by catching the -setuid() call and moving the tasks into the correct cgroup. - -We would ask Apache to modify their software to interface with libcgroup, but -this solution is less than optimal because a lot of userspace software would -have to be changed, and some authors might intentionally not interact with -libcgroup, which could create an exploit. The daemon is a simple, transparent -solution. - -USING THE DAEMON -================ -The daemon can be used as a service with the cgred script, which is shipped -as scripts/init.d/cgred. This script should be installed as /etc/init.d/cgred -and used like any other service. To start the daemon, - /etc/init.d/cgred start -To stop it, - /etc/init.d/cgred stop -The restart (stop,start), condrestart (same as restart, but only if the daemon -was already started), and status (print whether the daemon is started or -stopped) commands are also supported. An additional command, "reload", allows -you to reload the configuration file without stopping the daemon. - /etc/init.d/cgred reload -The cgred script automatically loads configuration from /etc/sysconfig/cgred.conf, -which is shipped as samples/cgred.conf. See that file for more information. - -If you choose not to run the daemon as a service, the following options are -currently supported: - --nodaemon Do not run as a daemon - --nolog Write log output to stdout instead of a log file - --config [FILE] Read rules configuration from FILE instead of - /etc/cgrules.conf - -You can ask the daemon to reload the rules configuration by sending it SIGUSR2. -The easiest way to do this is with the 'kill' command: - kill -s SIGUSR2 [PID] - -You can ask the daemon to reload the templates configuration by sending it -SIGUSR1. The easiest way to do this is with the 'kill' command: - kill -s SIGUSR1 [PID] - -TESTING -======= -The program setuid (found in tests/setuid.c) can help you test the daemon. By -default, this program attempts to change its UID to root and then idles until -you kill it. You can change the default behavior to use a different UID, or -you can uncomment the second block of code to instead attempt to change the -GID. - -In order to make sure that everything works, I used the following rules: - sjo cpu default - cgtest cpu cgtest - % memory default - @cgroup cpu,memory cgtest - peter cpu test1 - % memory test2 - @root * default - * * default - -The users 'sjo' and 'cgtest' were normal users. 'peter' is not a user on the -system. The group 'cgroup' is a group containing sjo,root,cgtest as members, -and the group 'root' contains only root. The cgroups 'default' and 'cgtest' -exist, while 'test1' and 'test2' do not. Currently, the daemon does not check -for the existance of 'test1', though this would be easier to do once the -parsing and caching logic is moved into libcgroup. - -I ran the following tests, all of which were successful: - - set UID to sjo (should move cpu controller into default) - - set UID to root (should move cpu,memory controllers into cgtest) - - set UID to cgtest (should move cpu controller into cgtest, memory - controller into default) - - set GID to root (should move all controllers into default) - - set GID to cgroup (should move cpu, memory into cgtest) - - set GID to users (should move all controllers into default) - -The parsing logic will skip the 'peter' rule as well as its multi-line -components (in this case "% memory test2"), because the user does not exist. -This should work for group rules, too. Attempting to setuid() or setgid() to a -user/group that doesn't exist will just return an error and not generate a -kernel event of the PROC_EVENT_UID or PROC_EVENT_GID type, so the daemon won't -do anything for it. - -CONCERNS/ISSUES -=============== - - Netlink can be unreliable, and the daemon might miss an event if the buffer - is full. One possible solution is to have one or two files that the kernel - can queue UID/GID changes in, and have the daemon read those files whenever - they are updated. From testing, this does not actually appear to be a real - problem, but it could become one with faster machines. - - The daemon does not care for namespaces at all, which can cause conflicts - with containers. If a user places his tasks into exec-based cgroups (such - as 'network' and 'development'), the daemon will not realize this and will - simply place them into the user's cgroup (so, sjo/ instead of sjo/network/). - -CHANGELOG -========= -V9: - - Updated documentation, because it was very old and incorrect. - - Reverted the changes to cgexec and cgclassify. - - New API function: cgroup_change_cgroup_uid_gid_flags(). - - Deprecated cgroup_change_cgroup_uid_gid(). - - Rewrote some of the rule matching and execution logic in api.c to be - faster, and easier to read. - - Changes all negative return values to positive values. As a side effect, - cgroup_parse_rules() now returns -1 when we get a match and we are using - non-cached rules. - - Changes CGROUP_FUSECACHE to CGFLAG_USECACHE. - - Flags are now enumerated (cgflags), instead of #defines. - -V8: - - Moved the event-handling logic back into the daemon, where it should be. - - Changed cgroup_parse_rules() to work with cached rules or non-cached rules. - The other parsing function is no longer needed, and should be deprecated. - - Non-cached rules now work with the same structs as cached rules. - - Modified cgroup_change_cgroup_uid_gid() with a new 'flags' parameter. - Currently, the only flag is "CGROUP_FUSECACHE" to use the cached rules logic - (or not). - - Added cgroup_rules_loaded() boolean, to check whether the cached rules have - been loaded yet, and cgroup_init_rules_cache() to load them. - - Modified cgexec and cgclassify to work with the new - cgroup_change_cgroup_uid_gid(). - -V7: - - Moved parsing and caching logic into libcgroup. - - Added locking mechanisms around the list of rules. - - Cleaned up #includes in cgrulesegnd.[h,c]. - - Added notification if netlink receive queue overflows. - - Added logic to catch SIGINT in addition to SIGTERM. - - New API functions: - - cgroup_free_rule(struct cgroup_rule*) - - cgroup_free_rule_list(struct cgroup_rule_list*) - - cgroup_parse_rules(void) - - cgroup_print_rules_config(FILE*) - - cgroup_reload_cached_rules(void) - - cgroup_change_cgroup_event(struct proc_event*, int, FILE*) - -V6: - - Wrote new parsing logic, which is cleaner and simpler. - - Added cgred script to enable using the daemon as a service. - - Wrote caching logic to cache rules table. - - Added the ability to force a reload of the rules table with SIGUSR2 signal. - - Added two structures to libcgroup: cgre_rule and cgre_rules_list - - New API function: cgroup_reload_cached_rules, which reloads the rules table. - - Added logging capabilities (default log is /root/cgrulesengd.conf) - -TODO -==== - - Find a way to replace Netlink, or at least clean up that code. - - Find a solution to the namespace problem. diff --git a/README_systemd b/README_systemd deleted file mode 100644 index 6733c2c4..00000000 --- a/README_systemd +++ /dev/null @@ -1,69 +0,0 @@ -Integration with systemd -======================== - -systemd is a system and service manager for Linux, compatible with SysV -and LSB init scripts. systemd heavily uses control groups to manage and control -services. - -Most of the libcgroup tools and APIs can be safely used on systems with systemd -without any problems. This document attempts to describe the configuration of -systemd and libcgroup so they can safely co-exist and mutually benefit each -other. - -References -========== -[1] http://www.freedesktop.org/wiki/Software/systemd -Systemd home page. - -[2] http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups -This is the most useful document describing systemd expectations on applications -(incl. libcgroup tools). - - -Compilation -=========== -As stated in [2], libcgroup should not interact with the 'name=systemd' -hierarchy. Compile libcgroup with the --enable-opaque-hierarchy configure option -to do so: - -./configure --enable-opaque-hierarchy=name=systemd - -Consequently, the 'name=systemd' hierarchy will not be visible to libcgroup and -all of its tools. For example, the lscgroup command will not list systemd -cgroups and the cgclear command will not remove them. - -Start-up and services -==================== - -Systemd automatically mounts all available controllers on system boot ('cpu' and -'cpuacct' together in one hierarchy by default) and can automatically put -service processes into control groups with configured parameters — by default, -each service is automatically put into the 'cpu,cpuacct:/system/$service_name' -control group. The System Administrator has full control of parameters in each -control group and of which controllers are used. Consult systemd -documentation, mainly systemd.conf(5) and systemd.exec(5) man pages, for -details. - -In the vast majority of use cases, this behavior is sufficient and libcgroup -does not need to be used. - -For specific use cases, e.g. when a different tree of control groups is needed, -libcgroup provides cgconfig service. This service can create arbitrary control -group hierarchies. In this case, follow these steps: - -1. Set 'DefaultControllers=' in /etc/systemd/system.conf so that systemd does -not create control groups for services automatically. - -2. Prepare /etc/cgconfig.conf and enable the cgconfig service. The service will -parse the /etc/cgconfig.conf file during machine boot and create all control -groups which are defined in it. The service automatically sets '+t' ("sticky") -bit on the tasks files as recommended in [2]. - -3. For each service that should start in a specific control group, add the -following lines into its unit file: - After=cgconfig.service - ControlGroup= - -This ensures the service is started only after cgconfig creates the necessary -hierarchy for it. It also tells systemd which control group it should use to -start the service. diff --git a/bootstrap.sh b/bootstrap.sh deleted file mode 100755 index 6e6dcbb5..00000000 --- a/bootstrap.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -ex - -if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then - cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ - chmod +x .git/hooks/pre-commit && \ - echo "Activated pre-commit hook." -fi - -# configure googletest -git submodule update --init --recursive -pushd googletest/googletest -git checkout release-1.8.0 -cmake -DBUILD_SHARED_LIBS=ON . -make -popd - -test -d m4 || mkdir m4 -autoreconf -fi -rm -fr autom4te.cache - -CFLAGS="$CFLAGS -g -O0" ./configure --sysconfdir=/etc --localstatedir=/var - -make clean diff --git a/configure.in b/configure.in deleted file mode 100644 index 891663dd..00000000 --- a/configure.in +++ /dev/null @@ -1,224 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. -# -# Copyright International Business Machines Corp. 2008 -# -# Authors: Balbir Singh -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -AC_PREREQ([2.69]) - -# In following section update all occurences of version, including soname -AC_INIT([libcgroup],[0.42]) - -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIRS([m4]) - -AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects]) - -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -# set library version, soname is libcgroup.so.MAJOR -AC_SUBST(LIBRARY_VERSION_MAJOR, 1) -AC_SUBST(LIBRARY_VERSION_MINOR, 0) -AC_SUBST(LIBRARY_VERSION_RELEASE, 42) - -# we do not want static libraries -#AC_DISABLE_STATIC - -AM_PROG_AR -LT_INIT - -AC_CONFIG_SRCDIR([src]) -AC_CONFIG_HEADER([config.h]) - -AC_ARG_ENABLE([bindings], - [AS_HELP_STRING([--enable-bindings],[enable python bindings [default=no]])], - [ - if test "x$enableval" = xno; then - with_bindings=false - else - with_bindings=true - fi - ], - [with_bindings = false]) -AM_CONDITIONAL([WITH_BINDINGS], [test x$with_bindings = xtrue]) - -# Process command line options -AC_ARG_ENABLE([tools], - [AS_HELP_STRING([--enable-tools],[compile libcgroup tools [default=yes]])], - [ - if test "x$enableval" = xno; then - with_tools=false - else - with_tools=true - fi - ], - [with_tools=true]) -AM_CONDITIONAL([WITH_TOOLS], [test x$with_tools = xtrue]) - -AC_ARG_ENABLE([pam], - [AS_HELP_STRING([--enable-pam],[compile libcgroup PAM module [default=yes]])], - [ - if test "x$enableval" = xno; then - with_pam=false - else - with_pam=true - fi - ], - [with_pam=true]) -AM_CONDITIONAL([WITH_PAM], [test x$with_pam = xtrue]) - -AC_ARG_ENABLE([daemon], - [AS_HELP_STRING([--enable-daemon],[compile libcgroup daemon [default=yes]])], - [ - if test "x$enableval" = xno; then - with_daemon=false - else - with_daemon=true - fi - ], - [with_daemon=true]) -AM_CONDITIONAL([WITH_DAEMON], [test x$with_daemon = xtrue]) - -AC_ARG_ENABLE([initscript-install], - [AS_HELP_STRING([--enable-initscript-install],[install init scripts [default=no]])], - [ - if test "x$enableval" = xno; then - with_initscript_install=false - else - with_initscript_install=true - fi - ], - [with_initscript_install=false]) -AM_CONDITIONAL([WITH_INITSCRIPT_INSTALL], [test x$with_initscript_install = xtrue]) - -socket_path="/var/run/cgred.socket" -AC_ARG_ENABLE([cgred-socket], - [AS_HELP_STRING([--enable-cgred-socket=PATH],[specify location of cgrulesengd communication socket - (default=/var/run/cgred.socket)])], - [ - if test "x$enableval" = xno -o "x$enableval" = xyes; then - AC_MSG_ERROR([Provide valid path with --enable-cgred-socket option.]) - else - socket_path="$enableval" - fi - ], []) -AC_DEFINE_UNQUOTED([CGRULE_CGRED_SOCKET_PATH],"$socket_path", [Cgrulesengd socket path]) - -pam_module_dir="$libdir/security" -AC_ARG_ENABLE([pam-module-dir], - [AS_HELP_STRING([--enable-pam-module-dir=PATH],[specify location of libcgroup PAM module - (default=$libdir/security)])], - [ - if test "x$enableval" = xno -o "x$enableval" = xyes; then - AC_MSG_ERROR([Provide valid path with --enable-pam-module-dir option.]) - else - pam_module_dir="$enableval" - fi - ], []) -AC_SUBST([pamlibdir],"$pam_module_dir") - -AC_ARG_ENABLE([opaque-hierarchy], - [AS_HELP_STRING([--enable-opaque-hierarchy=NAME],[specify name of a hierarchy which libcgroup should ignore, e.g. name=systemd - (default=none)])], - [ - if test "x$enableval" = xno -o "x$enableval" = xyes; then - AC_MSG_ERROR([Provide name of a hierarchy.]) - else - AC_DEFINE_UNQUOTED([OPAQUE_HIERARCHY], "$enableval", - [Define to ignore specific hierarchy.]) - fi - ], []) - -# Checks for programs. -AC_PROG_CXX -AC_PROG_CC -AC_PROG_YACC -if test "$YACC" = yacc; then - AC_CHECK_PROG([REALLY_YACC], [yacc], [yacc]) - if test "$REALLY_YACC" = ""; then - AC_MSG_ERROR([This program cannot be built unless a version of yacc is installed.]) - fi -fi -AM_PROG_LEX -if test "$LEX" != flex; then - AC_MSG_ERROR([This program cannot be built unless flex is installed.]) -fi -LT_INIT - -# Checks for header files. -AC_HEADER_DIRENT -AC_HEADER_STDC -AC_CHECK_HEADERS([limits.h mntent.h stdlib.h string.h sys/mount.h unistd.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_HEADER_STDBOOL -AC_C_CONST -AC_TYPE_UID_T -AC_C_INLINE -AC_TYPE_INT64_T -AC_TYPE_PID_T - -# Checks for library functions. -AC_FUNC_CHOWN -AC_FUNC_GETMNTENT -AC_FUNC_MALLOC -AC_FUNC_REALLOC -AC_FUNC_STAT -AC_CHECK_FUNCS([getmntent hasmntopt memset mkdir rmdir strdup]) - -if test x$with_pam = xtrue; then - AC_CHECK_LIB( - [pam], - [pam_syslog], - [ - dnl Override the default behavior of AC_CHECK_LIB, - dnl we don't want -lpam in LIBS. - : - ], - [AC_MSG_ERROR([Cannot compile PAM module without libpam!])]) - - AC_CHECK_HEADERS( - [security/pam_modules.h security/pam_modutil.h security/pam_ext.h], - [], - [AC_MSG_ERROR([Cannot compile PAM module without necessary - header files!])]) -fi - -AX_CODE_COVERAGE - -AC_CONFIG_FILES([Makefile - tests/Makefile - tests/ftests/Makefile - tests/gunit/Makefile - tests/tools/testenv.sh - tests/tools/Makefile - tests/tools/cgconfigparser/Makefile - tests/tools/cgclassify/Makefile - tests/tools/multimount/Makefile - tests/runlibcgrouptest.sh - src/Makefile - src/daemon/Makefile - src/tools/Makefile - src/pam/Makefile - src/bindings/Makefile - scripts/Makefile - scripts/init.d/cgconfig - scripts/init.d/cgred - samples/Makefile - include/Makefile - doc/Makefile - doc/man/Makefile - dist/Makefile - libcgroup.pc]) -AC_CONFIG_FILES([dist/libcgroup.spec:dist/libcgroup.spec.in]) -CFLAGS="$CFLAGS -Wall" -AC_OUTPUT - diff --git a/dist/.gitignore b/dist/.gitignore deleted file mode 100644 index a3725e16..00000000 --- a/dist/.gitignore +++ /dev/null @@ -1 +0,0 @@ -libcgroup.spec diff --git a/dist/Makefile.am b/dist/Makefile.am deleted file mode 100644 index 346b8b8a..00000000 --- a/dist/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = libcgroup.spec diff --git a/dist/cgconfig.service b/dist/cgconfig.service deleted file mode 100644 index e63f26dc..00000000 --- a/dist/cgconfig.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Control Group configuration service - -# The service should be able to start as soon as possible, -# before any 'normal' services: -DefaultDependencies=no -Conflicts=shutdown.target -Before=basic.target shutdown.target - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStart=/sbin/cgconfigparser -l /etc/cgconfig.conf -s 1664 -ExecStop=/sbin/cgclear -l /etc/cgconfig.conf -e - -[Install] -WantedBy=sysinit.target diff --git a/dist/libcgroup.spec.in b/dist/libcgroup.spec.in deleted file mode 100644 index 838290d8..00000000 --- a/dist/libcgroup.spec.in +++ /dev/null @@ -1,169 +0,0 @@ -%define soversion @LIBRARY_VERSION_MAJOR@.@LIBRARY_VERSION_MINOR@.@LIBRARY_VERSION_RELEASE@ -%define soversion_major @LIBRARY_VERSION_MAJOR@ - -Name: libcgroup -Summary: Tools and libraries to control and monitor control groups -Group: System Environment/Libraries -Version: @PACKAGE_VERSION@ -Release: 1%{?dist} -License: LGPLv2+ -URL: http://libcg.sourceforge.net/ -Source0: http://downloads.sourceforge.net/libcg/%{name}-%{version}.tar.bz2 -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -BuildRequires: pam-devel -BuildRequires: byacc -BuildRequires: flex -BuildRequires: coreutils -Requires(pre): shadow-utils -Requires(post): chkconfig, /sbin/service -Requires(preun): /sbin/chkconfig - -%description -Control groups infrastructure. The tools and library help manipulate, control, -administrate and monitor control groups and the associated controllers. - -%package pam -Summary: A Pluggable Authentication Module for libcgroup -Group: System Environment/Base -Requires: libcgroup = %{version}-%{release} - -%description pam -Linux-PAM module, which allows administrators to classify the user's login -processes to pre-configured control group. - -%package devel -Summary: Development libraries to develop applications that utilize control groups -Group: Development/Libraries -Requires: libcgroup = %{version}-%{release} - -%description devel -It provides API to create/delete and modify cgroup nodes. It will also in the -future allow creation of persistent configuration for control groups and -provide scripts to manage that configuration. - -%prep -%setup -q - -%build -%configure --bindir=/bin --sbindir=/sbin --libdir=%{_libdir} --enable-initscript-install --enable-pam-module-dir=/%{_lib}/security - -make %{?_smp_mflags} - - -%install -rm -rf $RPM_BUILD_ROOT -make DESTDIR=$RPM_BUILD_ROOT install - -# install config files -mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig -cp samples/cgred.conf $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/cgred.conf -cp samples/cgconfig.sysconfig $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/cgconfig -cp samples/cgconfig.conf $RPM_BUILD_ROOT/%{_sysconfdir}/cgconfig.conf -cp samples/cgrules.conf $RPM_BUILD_ROOT/%{_sysconfdir}/cgrules.conf -cp samples/cgsnapshot_blacklist.conf $RPM_BUILD_ROOT/%{_sysconfdir}/cgsnapshot_blacklist.conf - -# sanitize pam module, we need only pam_cgroup.so -mv -f $RPM_BUILD_ROOT/%{_lib}/security/pam_cgroup.so.*.*.* $RPM_BUILD_ROOT/%{_lib}/security/pam_cgroup.so -rm -f $RPM_BUILD_ROOT/%{_lib}/security/pam_cgroup.la $RPM_BUILD_ROOT/%{_lib}/security/pam_cgroup.so.* - -# move the libraries to / -mkdir -p $RPM_BUILD_ROOT/%{_lib} -mv -f $RPM_BUILD_ROOT/%{_libdir}/libcgroup.so.%{soversion} $RPM_BUILD_ROOT/%{_lib} -rm -f $RPM_BUILD_ROOT/%{_libdir}/libcgroup.so.%{soversion_major} -ln -sf libcgroup.so.%{soversion} $RPM_BUILD_ROOT/%{_lib}/libcgroup.so.%{soversion_major} -ln -sf ../../%{_lib}/libcgroup.so.%{soversion} $RPM_BUILD_ROOT/%{_libdir}/libcgroup.so -rm -f $RPM_BUILD_ROOT/%{_libdir}/*.la - -%clean -rm -rf $RPM_BUILD_ROOT - -%pre -getent group cgred >/dev/null || groupadd cgred - -%post -/sbin/ldconfig -/sbin/chkconfig --add cgred -/sbin/chkconfig --add cgconfig - -%preun -if [ $1 = 0 ]; then - /sbin/service cgred stop > /dev/null 2>&1 || : - /sbin/service cgconfig stop > /dev/null 2>&1 || : - /sbin/chkconfig --del cgconfig - /sbin/chkconfig --del cgred -fi - -%postun -p /sbin/ldconfig - -%files -%defattr(-,root,root,-) -%config(noreplace) %{_sysconfdir}/sysconfig/cgred.conf -%config(noreplace) %{_sysconfdir}/sysconfig/cgconfig -%config(noreplace) %{_sysconfdir}/cgconfig.conf -%config(noreplace) %{_sysconfdir}/cgrules.conf -%config(noreplace) %{_sysconfdir}/cgsnapshot_blacklist.conf -/%{_lib}/libcgroup.so.* -%attr(2755, root, cgred) /bin/cgexec -/bin/cgclassify -/bin/cgcreate -/bin/cgget -/bin/cgset -/bin/cgdelete -/bin/lscgroup -/bin/lssubsys -/sbin/cgconfigparser -/sbin/cgrulesengd -/sbin/cgclear -/bin/cgsnapshot -%attr(0644, root, root) %{_mandir}/man1/* -%attr(0644, root, root) %{_mandir}/man5/* -%attr(0644, root, root) %{_mandir}/man8/* -%attr(0755,root,root) %{_initrddir}/cgconfig -%attr(0755,root,root) %{_initrddir}/cgred - -%doc COPYING INSTALL README_daemon - -%files pam -%defattr(-,root,root,-) -%attr(0755,root,root) /%{_lib}/security/pam_cgroup.so -%doc COPYING INSTALL - -%files devel -%defattr(-,root,root,-) -%{_includedir}/libcgroup.h -%{_includedir}/libcgroup/*.h -%{_libdir}/libcgroup.* -/%{_libdir}/pkgconfig/libcgroup.pc -%doc COPYING INSTALL - - -%changelog -* Tue Nov 2 2010 Jan Safranek 0.37.rc1-1 -- Add cgsnapshot -* Thu Feb 18 2010 Dhaval Giani 0.36.rc1-1 -- Add pkgconfig file -* Tue Jan 19 2010 Balbir Singh 0.35.1 -- Integrate Jan's fixes for distributing cgget and initscripts -* Thu Oct 22 2009 Jan Safranek 0.34-1 -- Update to latest upstream -- Split PAM module to separate subpackage -* Tue Feb 24 2009 Balbir Singh 0.33-1 -- Update to 0.33, spec file changes to add Makefiles and pam_cgroup module -* Fri Oct 10 2008 Dhaval Giani 0.32-1 -- Update to latest upstream -* Thu Sep 11 2008 Dhaval Giani 0.31-1 -- Update to latest upstream -* Sat Aug 2 2008 Dhaval Giani 0.1c-3 -- Change release to fix broken upgrade path -* Wed Jun 11 2008 Dhaval Giani 0.1c-1 -- Update to latest upstream version -* Tue Jun 3 2008 Balbir Singh 0.1b-3 -- Add post and postun. Also fix Requires for devel to depend on base n-v-r -* Sat May 31 2008 Balbir Singh 0.1b-2 -- Fix makeinstall, Source0 and URL (review comments from Tom) -* Mon May 26 2008 Balbir Singh 0.1b-1 -- Add a generatable spec file -* Tue May 20 2008 Balbir Singh 0.1-1 -- Get the spec file to work -* Tue May 20 2008 Dhaval Giani 0.01-1 -- The first version of libcg diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index 5822dc16..00000000 --- a/doc/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -SUBDIRS = man - diff --git a/doc/internal/release-github.txt b/doc/internal/release-github.txt deleted file mode 100644 index f7e59dd9..00000000 --- a/doc/internal/release-github.txt +++ /dev/null @@ -1,25 +0,0 @@ -1. Update version in configure.in - a. AC_INIT([libcgroup],[0.XX]) - b. Add an .rcY to the end, e.g. 0.XX.rcY -2. Build - a. Run ./bootstrap.sh - b. Run ./configure - c. Run make check - d. Run make dist -3. Tag the Release - a. git tag -s -a -m "v0.XX.rcY" v0.XX.rcY -4. Push to github - a. git push origin v0.XX.rcY - b. Generate a checksum for the *.tar.gz and *.tar.bz2 and ... - sha256sum > libseccomp-X.Y.Z.tar.gz.SHA256SUM - c. Upload the zips and checksums to the github release - d. Email libcg-devel about the new release w/ the changelog - git shortlog v0.XX.rc(Y-1)..v0.XX.rcY -5. Verify continuous integration passes - a. Verify TravisCI, code coverage, etc. all pass - b. If the CI checks fail, fix it, and go back to step #1 -6. Fix issues identified as critical for current rc(Y+1) - a. If any issues fixed, update the rcY number and go to step #1 - b. If no issues, go to step #7 -7. Release Notes -8. Do steps #1 through #5 (except step #1b) diff --git a/doc/internal/release.txt b/doc/internal/release.txt deleted file mode 100644 index 35264d72..00000000 --- a/doc/internal/release.txt +++ /dev/null @@ -1,33 +0,0 @@ -Libcgroup release procedure -=========================== -Please follow the following steps (TODO: Automate these steps) -1. Check, that every new or changed feature since last release is reflected in - README and/or man pages. -2. Bump soname of libcgroup shared objects if needed - LIBRARY_VERSION_MAJOR, - _MINOR and _RELEASE in configure.in. -3. Prepare release candidate (X.YY-rcZ - X.YY = version, Z - prerelease -umber): - a. Update AC_INIT(X.YY.rcZ) in configure.in. - b. Run 'autoreconf -i' to generate the configure file again, with the - new release number. - c. Run './configure' to generate Makefile and dist/libcgroup.spec with - correct version numbers. - d. Run 'make dist' to create tarball. Fix Makefile.am files if - something goes wrong. - The tarball should contain everything needed for compilation with - simple sh, make and (optionally) rpmbuild, among others: - libcgroup-X.YY.rcZ/configure - libcgroup-X.YY.rcZ/dist/libcgroup.spec - e. Try to build rpms ('rpmbuild -ta libcgroup-X.YY.rcZ.tar.gz'), fix - errors in dist/libcgroup.spec.in file if something goes wrong. - f. Tag the pre-release in git. - g. Publish the pre-release libcgroup-X.YY.rcZ.tar.gz and announce it on - the libgroup-devel list with a changelog (git shortlog A..B is your - friend). - h. Test the pre-release and go to a) if new one is needed. - During this period, ABI of newly introduced shared symbols is *not* - stable and may change, if there is very good reason to break it. - -5. Finally release official version using the same procedure as in step 3., - only without the .rcZ version number suffix. -6. Update topic on #libcgroup IRC channel. diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am deleted file mode 100644 index 26338d82..00000000 --- a/doc/man/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -man_MANS = cgclassify.1 cgconfig.conf.5 cgconfigparser.8 cgexec.1 cgred.conf.5 \ - cgrules.conf.5 cgrulesengd.8 cgcreate.1 cgset.1 cgclear.1 cgget.1 \ - cgdelete.1 lssubsys.1 lscgroup.1 cgsnapshot.1 - -EXTRA_DIST = $(man_MANS) - diff --git a/doc/man/cgclassify.1 b/doc/man/cgclassify.1 deleted file mode 100644 index 1facd2b2..00000000 --- a/doc/man/cgclassify.1 +++ /dev/null @@ -1,82 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Varekova . - -.TH CGCLASSIFY 1 2009-03-15 "Linux" "libcgroup Manual" -.SH NAME -cgclassify \- move running task(s) to given cgroups - -.SH SYNOPSIS -\fBcgclassify\fR [\fB-g\fR <\fIcontrollers>:] [--sticky | --cancel-sticky] <\fIpidlist\fR> - -.SH DESCRIPTION -this command moves processes defined by the list -of processes -(\fBpidlist\fR) -to the given control groups. - -The pids in the pidlist are separated by spaces - -.TP -.B -g : -defines the control groups where the task will be moved. -\fBcontrollers\fR is a list of controllers and -\fBpath\fR is the relative path to control groups -in the given controllers list. - -This flag can be used multiple times to -define multiple pairs of lists of controllers -and relative paths. -Instead of the list of all mounted controllers, -the wildcard \fB*\fR can be used. - -If this option is not used then -\fBcgclassify\fR will automatically move the task to a -control group based on \fB/etc/cgrules.conf\fR. - -.TP -.B --sticky -If this option is used, the daemon of service cgred (cgrulesengd process) -does not change both the specified \fBpidlist\fR and their children tasks. -Without this option, the daemon does not change the specified \fBpidlist\fR -but it automatically changes their child tasks to the right cgroup based on -\fB/etc/cgrules.conf\fR. - -.TP -.B --cancel-sticky -If this option is used, the daemon of service cgred (cgrulesengd process) -can automatically change both the specified \fBpidlist\fR and their child -tasks to the right cgroup based on \fB/etc/cgrules.conf\fR. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH FILES -.TP -.B /etc/cgrules.conf -default libcgroup configuration file -.TP -.B /etc/cgrules.d -default libcgroup configuration files directory - -.SH EXAMPLES -.TP -.B cgclassify -g cpu:student 1234 -moves process with pid number 1234 to control group student in cpu hierarchy. - -.TP -.B cgclassify 1234 -moves process with pid number 1234 to control groups based on -\fB/etc/cgrules.conf\fR configuration file. - -.TP -.B cgclassify --sticky -g cpu:/student 1234 -moves process with pid number 1234 to control group student in cpu hierarchy. -The daemon of service cgred does not change cgroups of pid 1234 and its children -(based on \fB/etc/cgrules.conf\fR). - -.SH SEE ALSO -cgrules.conf (5), cgexec (1) - diff --git a/doc/man/cgclear.1 b/doc/man/cgclear.1 deleted file mode 100644 index 241a0956..00000000 --- a/doc/man/cgclear.1 +++ /dev/null @@ -1,66 +0,0 @@ -.\" Copyright IBM Corporation. 2009. -.\" Written by Dhaval Giani . - -.TH CGCLEAR 1 2009-10-23 "Linux" "libcgroup Manual" -.SH NAME -cgclear \- unload the cgroup filesystem - -.SH SYNOPSIS -\fBcgclear\fR [\fB-e\fR] [\fB-l\fR <\fIfilename\fR>] [\fB-L\fR <\fIdirectory\fR>] [...] - -.SH DESCRIPTION - -Without parameters, this command moves all the tasks inside the various cgroups -to the root cgroup, deletes all the cgroups and finally -unmounts the cgroup filesystem from the system. - -If one or more config files are specified, only groups defined in the config -files are removed. The files are processed in reverse order, i.e. the last -file on command line is processed first, so \fBcgclear\fR can have the same -command line arguments as appropriate \fBcgconfigparser\fR. - -.TP -.B -l, --load= -specifies the config file to read. This option can be used multiple times and -can be mixed with \fB-L\fR option. - -.TP -.B -L, --load-directory= -specifies the directory, which is searched for configuration files. All files -in this directory will be processed in alphabetical order as they were specified -by \fB-l\fR option. This option can be used multiple times and -can be mixed with \fB-l\fR option. - -.TP -.B -e -specifies that only empty groups should be removed. If a group defined in a -config file has tasks inside or has a subgroup, it won't be removed. This -option works only with \fB-l\fR or \fB-L\fR options. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH FILES -.TP -.B /etc/cgconfig.conf -default templates file -.TP -.B /etc/cgconfig.d/ -default templates files directory -.RE - - -.SH EXAMPLES -.TP -.B cgclear -unload the whole cgroup filesystem - -.TP -.B cgclear -l /etc/cgconfig.conf -unload a subsystem of cgroup filesystem based on \fB/etc/cgconfig.conf\fR definition. - -.SH SEE ALSO -cgconfigparser(1), cgconfig.conf(5) diff --git a/doc/man/cgconfig.conf.5 b/doc/man/cgconfig.conf.5 deleted file mode 100644 index 2a5c4eef..00000000 --- a/doc/man/cgconfig.conf.5 +++ /dev/null @@ -1,824 +0,0 @@ -.TH CGCONFIG.CONF 5 -.\"*********************************** -.SH NAME -cgconfig.conf \- libcgroup configuration file -.\"*********************************** -.SH DESCRIPTION -.B "cgconfig.conf" -is a configuration file used by -.B libcgroup -to define control groups, their parameters and their mount points. -The file consists of -.I mount -, -.I group -and -.I default -sections. These sections can be in arbitrary order and all of them are -optional. Any line starting with '#' is considered a comment line and -is ignored. -.LP -.I mount -section has this form: -.RS -.nf -.ft B -.sp -mount { -.RS -.ft B - = ; -.I "..." -.RE -.ft B -} -.ft R -.fi -.RE - -.TP -.B controller -Name of the kernel subsystem. The list of subsystems supported by the kernel -can be found in -.I /proc/cgroups -file. Named hierarchy can be specified as controller -\fB"name="\fR. Do not forget to use double quotes around -this controller name (see examples below). Apart from named hierarchy, -additional mount options may be specified by putting the controller and -the options in quotes. Options supported are \fB nosuid, noexec\fR and\fB nodev\fR. - -.B Libcgroup -merges all subsystems mounted to the same directory (see -Example 1) and the directory is mounted only once. - -.TP -.B path -The directory path where the group hierarchy associated to a given -controller shall be mounted. The directory is created -automatically on cgconfig service startup if it does not exist and -is deleted on service shutdown. -.LP - -If no -.I mount -section is specified, no controllers are mounted. - -.I group -section has this form: -.RS -.nf -.ft B -.sp -group { -.RS -.ft B -[permissions] - { -.RS -.ft B - = ; -.I "..." -.RE -.ft B -} -.I "..." -.RE -.ft B -} -.ft R -.fi -.RE - -.TP -.B name -Name of the control group. It can contain only characters, which are -allowed for directory names. -The groups form a tree, i.e. a control group can contain zero or more -subgroups. Subgroups can be specified using '/' delimiter. - -The root control group is always created automatically in all hierarchies -and it is the base of the group hierarchy. It can be explicitly specified in -.B cgconfig.conf -by using '.' as group name. This can be used e.g. to set its permissions, -as shown in Example 6. - -When the parent control group of a subgroup is not specified -it is created automatically. - -.TP -.B permissions -Permissions of the given control group on mounted filesystem. -.I root -has always permission to do anything with the control group. -Permissions have the following syntax: -.RS 17 -.ft B -.nf -perm { -.RS -.ft B -task { -.RS -.ft B -uid = ; -gid = ; -fperm = -.RE -} -admin { -.RS -uid = ; -gid = ; -dperm = -fperm = -.RE -} -.RE -} -.fi -.RE -.ft R - -.RS -.TP 17 -.B "task user/group" -Name of the user and the group, which own the -.I tasks -file of the control group. Given fperm then specify the file permissions. -Please note that the given value is not used as was specified. Instead, -current file owner permissions are used as a "umask" for group and others -permissions. For example if fperm = 777 then both group and others will get -the same permissions as the file owner. -.TP 17 -.B "admin user/group" -Name of the user and the group which own the rest of control group's -files. Given fperm and dperm control file and directory permissions. -Again, the given value is masked by the file/directory owner permissions. -.LP -Permissions are only apply to the enclosing control group and are not -inherited by subgroups. If there is no -.B perm -section in the control group definition, -.I root:root -is the owner of all files and default file permissions are preserved if -fperm resp. dperm are not specified. -.RE -.TP -.B controller -Name of the kernel subsystem. -The section can be -empty, default kernel parameters will be used in this case. By -specifying -.B controller -the control group and all its parents are controlled by the specific -subsystem. One control group can be controlled by multiple subsystems, -even if the subsystems are mounted on different directories. Each -control group must be controlled by at least one subsystem, so that -.B libcgroup -knows in which hierarchies the control group should be created. - -The parameters of the given controller can be modified in the following -section enclosed in brackets. -.RS -.TP -.B param name -Name of the file to set. Each controller can have zero or more -parameters. -.TP -.B param value -Value which should be written to the file when the control group is -created. If it is enclosed in double quotes `"', it can contain spaces -and other special characters. -.RE - -If no -.I group -section is specified, no groups are created. - -.I default -section has this form: -.RS -.nf -.ft B -.sp -default { -.RS -.ft B -perm { -.RS -.ft B -task { -.RS -.ft B -uid = ; -gid = ; -fperm = -.RE -} -admin { -.RS -uid = ; -gid = ; -dperm = -fperm = -.RE -} -.RE -} -.RE -} -.ft R -.fi -.RE - -Content of the -.B perm -section has the same form as in -.I group -section. The permissions defined here specify owner and permissions of -groups and files of all groups, which do not have explicitly specified -their permissions in their -.I group -section. - -.I template -section has the same structure as -.B group -section. Template name uses the same templates string as -.B cgrules.conf -destination tag (see (\fBcgrules.conf\fR (5)). -Template definition is used as a control group definition for rules in -\fBcgrules.conf\fR (5) with the same destination name. -Templates does not use -.B default -section settings. - -.I /etc/cgconfig.d/ -directory can be used for additional configuration files. cgrulesengd searches this directory for additional templates. - -.\"********************************************" -.SH EXAMPLES -.LP -.SS Example 1 -.LP -The configuration file: -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -cpuacct = /mnt/cgroups/cpu; -.RE -} -.fi -.RE - -creates the hierarchy controlled by two subsystems with no groups -inside. It corresponds to the following operations: -.LP -.RS -.nf -mkdir /mnt/cgroups/cpu -mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/cpu -.fi -.RE - -.SS Example 2 -.LP -The configuration file: -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -"name=scheduler" = /mnt/cgroups/cpu; -"name=noctrl" = /mnt/cgroups/noctrl; -.RE -} - -group daemons { -.RS -cpu { -.RS -cpu.shares = "1000"; -.RE -} -.RE -} -group test { -.RS -"name=noctrl" { -} -.RE -} -.RE -.fi -creates two hierarchies. One hierarchy named \fBscheduler\fR controlled by cpu -subsystem, with group \fBdaemons\fR inside. Second hierarchy is named -\fBnoctrl\fR without any controller, with group \fBtest\fR. It corresponds to -following operations: -.LP -.RS -.nf -mkdir /mnt/cgroups/cpu -mount -t cgroup -o cpu,name=scheduler cpu /mnt/cgroups/cpu -mount -t cgroup -o none,name=noctrl none /mnt/cgroups/noctrl - -mkdir /mnt/cgroups/cpu/daemons -echo 1000 > /mnt/cgroups/cpu/daemons/www/cpu.shares - -mkdir /mnt/cgroups/noctrl/tests -.fi -.RE - -The -.I daemons -group is created automatically when its first subgroup is -created. All its parameters have the default value and only root can -access group's files. -.LP -Since both -.I cpuacct -and -.I cpu -subsystems are mounted to the same directory, all -groups are implicitly controlled also by -.I cpuacct -subsystem, even if there is no -.I cpuacct -section in any of the groups. -.RE - -.SS Example 3 -.LP -The configuration file: -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -cpuacct = /mnt/cgroups/cpu; -.RE -} - -group daemons/www { -.RS -perm { -.RS -task { -.RS -uid = root; -gid = webmaster; -fperm = 770; -.RE -} -admin { -.RS -uid = root; -gid = root; -dperm = 775; -fperm = 744; -.RE -} -.RE -} -cpu { -.RS -cpu.shares = "1000"; -.RE -} -.RE -} - -group daemons/ftp { -.RS -perm { -.RS -task { -.RS -uid = root; -gid = ftpmaster; -fperm = 774; -.RE -} -admin { -.RS -uid = root; -gid = root; -dperm = 755; -fperm = 700; -.RE -} -.RE -} -cpu { -.RS -cpu.shares = "500"; -.RE -} -.RE -} -.RE -.fi -creates the hierarchy controlled by two subsystems with one group and -two subgroups inside, setting one parameter. -It corresponds to the following operations (except for file permissions -which are little bit trickier to emulate via chmod): - -.LP -.RS -.nf -mkdir /mnt/cgroups/cpu -mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/cpu - -mkdir /mnt/cgroups/cpu/daemons - -mkdir /mnt/cgroups/cpu/daemons/www -chown root:root /mnt/cgroups/cpu/daemons/www/* -chown root:webmaster /mnt/cgroups/cpu/daemons/www/tasks -echo 1000 > /mnt/cgroups/cpu/daemons/www/cpu.shares - - # + chmod the files so the result looks like: - # ls -la /mnt/cgroups/cpu/daemons/www/ - # admin.dperm = 755: - # drwxr-xr-x. 2 root webmaster 0 Jun 16 11:51 . - # - # admin.fperm = 744: - # --w-------. 1 root webmaster 0 Jun 16 11:51 cgroup.event_control - # -r--r--r--. 1 root webmaster 0 Jun 16 11:51 cgroup.procs - # -r--r--r--. 1 root webmaster 0 Jun 16 11:51 cpuacct.stat - # -rw-r--r--. 1 root webmaster 0 Jun 16 11:51 cpuacct.usage - # -r--r--r--. 1 root webmaster 0 Jun 16 11:51 cpuacct.usage_percpu - # -rw-r--r--. 1 root webmaster 0 Jun 16 11:51 cpu.rt_period_us - # -rw-r--r--. 1 root webmaster 0 Jun 16 11:51 cpu.rt_runtime_us - # -rw-r--r--. 1 root webmaster 0 Jun 16 11:51 cpu.shares - # -rw-r--r--. 1 root webmaster 0 Jun 16 11:51 notify_on_release - # - # tasks.fperm = 770 - # -rw-rw----. 1 root webmaster 0 Jun 16 11:51 tasks - - -mkdir /mnt/cgroups/cpu/daemons/ftp -chown root:root /mnt/cgroups/cpu/daemons/ftp/* -chown root:ftpmaster /mnt/cgroups/cpu/daemons/ftp/tasks -echo 500 > /mnt/cgroups/cpu/daemons/ftp/cpu.shares - - # + chmod the files so the result looks like: - # ls -la /mnt/cgroups/cpu/daemons/ftp/ - # admin.dperm = 755: - # drwxr-xr-x. 2 root ftpmaster 0 Jun 16 11:51 . - # - # admin.fperm = 700: - # --w-------. 1 root ftpmaster 0 Jun 16 11:51 cgroup.event_control - # -r--------. 1 root ftpmaster 0 Jun 16 11:51 cgroup.procs - # -r--------. 1 root ftpmaster 0 Jun 16 11:51 cpuacct.stat - # -rw-------. 1 root ftpmaster 0 Jun 16 11:51 cpuacct.usage - # -r--------. 1 root ftpmaster 0 Jun 16 11:51 cpuacct.usage_percpu - # -rw-------. 1 root ftpmaster 0 Jun 16 11:51 cpu.rt_period_us - # -rw-------. 1 root ftpmaster 0 Jun 16 11:51 cpu.rt_runtime_us - # -rw-------. 1 root ftpmaster 0 Jun 16 11:51 cpu.shares - # -rw-------. 1 root ftpmaster 0 Jun 16 11:51 notify_on_release - # - # tasks.fperm = 774: - # -rw-rw-r--. 1 root ftpmaster 0 Jun 16 11:51 tasks - -.fi -.RE - -The -.I daemons -group is created automatically when its first subgroup is -created. All its parameters have the default value and only root can -access the group's files. -.LP -Since both -.I cpuacct -and -.I cpu -subsystems are mounted to the same directory, all -groups are implicitly also controlled by the -.I cpuacct -subsystem, even if there is no -.I cpuacct -section in any of the groups. -.RE - -.SS Example 4 -.LP -The configuration file: - -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -cpuacct = /mnt/cgroups/cpuacct; -.RE -} - -group daemons { -.RS -cpuacct{ -} -cpu { -} -.RE -} -.fi -.RE -creates two hierarchies and one common group in both of them. -It corresponds to the following operations: -.LP -.RS -.nf -mkdir /mnt/cgroups/cpu -mkdir /mnt/cgroups/cpuacct -mount -t cgroup -o cpu cpu /mnt/cgroups/cpu -mount -t cgroup -o cpuacct cpuacct /mnt/cgroups/cpuacct - -mkdir /mnt/cgroups/cpu/daemons -mkdir /mnt/cgroups/cpuacct/daemons -.fi -.RE - -In fact there are two groups created. One in the -.I cpuacct -hierarchy, the second in the -.I cpu -hierarchy. These two groups have nothing in common and can -contain different subgroups and different tasks. - -.SS Example 5 -.LP - -The configuration file: - -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -cpuacct = /mnt/cgroups/cpuacct; -.RE -} - -group daemons { -.RS -cpuacct{ -} -.RE -} - -group daemons/www { -.RS -cpu { -.RS -cpu.shares = "1000"; -.RE -} -.RE -} - -group daemons/ftp { -.RS -cpu { -.RS -cpu.shares = "500"; -.RE -} -.RE -} -.fi -.RE -creates two hierarchies with few groups inside. One of the groups -is created in both hierarchies. - -It corresponds to the following operations: -.LP -.RS -.nf -mkdir /mnt/cgroups/cpu -mkdir /mnt/cgroups/cpuacct -mount -t cgroup -o cpu cpu /mnt/cgroups/cpu -mount -t cgroup -o cpuacct cpuacct /mnt/cgroups/cpuacct - -mkdir /mnt/cgroups/cpuacct/daemons -mkdir /mnt/cgroups/cpu/daemons -mkdir /mnt/cgroups/cpu/daemons/www -echo 1000 > /mnt/cgroups/cpu/daemons/www/cpu.shares -mkdir /mnt/cgroups/cpu/daemons/ftp -echo 500 > /mnt/cgroups/cpu/daemons/ftp/cpu.shares -.fi -.RE -Group -.I daemons -is created in both hierarchies. In the -.I cpuacct -hierarchy the group is explicitly mentioned in the configuration -file. In the -.I cpu -hierarchy the group is created implicitly when -.I www -is created there. These two groups have nothing in common, for example -they do not share processes and subgroups. Groups -.I www -and -.I ftp -are created only in the -.I cpu -hierarchy and are not controlled by the -.I cpuacct -subsystem. - -.SS Example 6 -.LP -The configuration file: -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -cpuacct = /mnt/cgroups/cpu; -.RE -} - -group . { -.RS -perm { -.RS -task { -.RS -uid = root; -gid = operator; -.RE -} -admin { -.RS -uid = root; -gid = operator; -.RE -} -.RE -} -cpu { -} -.RE -} - -group daemons { -.RS -perm { -.RS -task { -.RS -uid = root; -gid = daemonmaster; -.RE -} -admin { -.RS -uid = root; -gid = operator; -.RE -} -.RE -} -cpu { -} -.RE -} -.RE -.fi -creates the hierarchy controlled by two subsystems with one group having some -special permissions. -It corresponds to the following operations: -.LP -.RS -.nf -mkdir /mnt/cgroups/cpu -mount -t cgroup -o cpu,cpuacct cpu /mnt/cgroups/cpu - -chown root:operator /mnt/cgroups/cpu/* -chown root:operator /mnt/cgroups/cpu/tasks - -mkdir /mnt/cgroups/cpu/daemons -chown root:operator /mnt/cgroups/cpu/daemons/* -chown root:daemonmaster /mnt/cgroups/cpu/daemons/tasks -.fi -.RE - -Users which are members of the -.I operator -group are allowed to administer the control groups, i.e. create new control -groups and move processes between these groups without having root -privileges. - -Members of the -.I daemonmaster -group can move processes to the -.I daemons -control group, but they can not move the process out of the group. Only the -.I operator -or root can do that. - -.SS Example 7 -.LP -The configuration file: - -.LP -.RS -.nf -mount { -.RS -cpu = /mnt/cgroups/cpu; -cpuacct = /mnt/cgroups/cpuacct; -.RE -} - -group students { -.RS -cpuacct{ -} -cpu { -} -.RE -} - -template students/%u { -.RS -cpuacct{ -} -cpu { -} -.RE -} - -mkdir /mnt/cgroups/cpu/daemons -mkdir /mnt/cgroups/cpuacct/daemons -.fi -.RE - -The situation is the similar as in Example 4. The only difference is template, -which is used if some rule uses "/students/%u" as a destination. - -.SS Example 8 -.LP -The configuration file: - -.LP -.RS -.nf -mount { -.RS -"cpu,nodev,nosuid,noexec" = /mnt/cgroups/cpu; -.RE -} - -.fi -.RE - -This is the same as -mount -t cgroup cgroup -o nodev,nosuid,noexec,cpu /mnt/cgroups/cpu -It mounts the cpu controller with MS_NODEV, MS_NOSUID and MS_NOEXEC -options passed. - - -.SH RECOMMENDATIONS -.SS Keep hierarchies separated -Having multiple hierarchies is perfectly valid and can be useful -in various scenarios. To keeps things clean, do not -create one group in multiple hierarchies. Examples 4 and 5 show -how unreadable and confusing it can be, especially when reading -somebody elses configuration file. - -.SS Explicit is better than implicit -.B libcgroup -can implicitly create groups which are needed for the creation of -configured subgroups. This may be useful and save some typing in -simple scenarios. When it comes to multiple hierarchies, it's -better to explicitly specify all groups and all controllers -related to them. - -.SH FILES -.TP -.B /etc/cgconfig.conf -default libcgroup configuration file -.TP -.B /etc/cgconfig.d/ -default libcgroup configuration files directory - -.SH SEE ALSO -cgconfigparser (8) - -.SH BUGS -Parameter values must be single strings without spaces. -Parsing of quoted strings is not implemented. - -.SH - diff --git a/doc/man/cgconfigparser.8 b/doc/man/cgconfigparser.8 deleted file mode 100644 index 8fff95f4..00000000 --- a/doc/man/cgconfigparser.8 +++ /dev/null @@ -1,92 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Varekova . - -.TH CGCONFIGPARSER 8 2009-03-16 "Linux" "libcgroup Manual" -.SH NAME - -cgconfigparser \- setup control group file system - -.SH SYNOPSIS -\fBcgconfigparser\fR [\fB-h\fR] [\fB-l\fR \fI\fR] [\fB-L\fR \fI\fR] [...] - -.SH OPTIONS -.TP -.B -h, --help -Displays help. -.TP -.B -l, --load=FILE -Parses the control groups configuration file -Sets up the control group file system -defined by the configuration file and mounts -mount points defined by the configuration file. -The format of the file is described in -\fBcgconfig.conf\fR. This option can be used multiple times and can be mixed -with \fB-L\fR option. - -.TP -.B -L, --load-directory=DIR -Finds all files in given directory and parses them in alphabetical order -like they were specified by \fB-l\fR option. This option can be used -multiple times and can be mixed with \fB-l\fR option. - -.TP -.B -a : -defines the default owner of the -rest of the defined control group’s files. These users are -allowed to set subsystem parameters and create subgroups. -The default value is the same as has the parent cgroup. - -.TP -.B -d, --dperm=mode -sets the default permissions of a control groups directory. -The permissions needs to be specified as octal numbers e.g. -\fB-d 775\fR. - -.TP -.B -f, --fperm=mode -sets the default permissions of the control group files. -The permissions needs to be specified as octal numbers e.g. -\fB-f 775\fR. -The value is not used as given because the current owner's -permissions are used as an umask (so 777 will set group and -others permissions to the owners permissions). - -.TP -.B -s, --tperm=mode -sets the default permissions of the control group tasks files. -The permissions needs to be specified as octal numbers e.g. -\fB-f 775\fR. -The value is not used as given because the current owner's -permissions are used as an umask (so 777 will set group and -others permissions to the owners permissions). - -.TP -.B -t : -defines the default owner of tasks file of the defined control -group. I.e. this user and members -of this group have write access to the file. - -.LP - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH FILES -.TP -.B /etc/cgconfig.conf -default libcgroup configuration file -.TP -.B /etc/cgconfig.d/ -default libcgroup configuration files directory - -.SH EXAMPLES -.TP -.B cgconfigparser -l /etc/cgconfig.conf -setup control group file system based on \fB/etc/cgconfig.conf\fR configuration file - - -.SH SEE ALSO -cgconfig.conf (5) diff --git a/doc/man/cgcreate.1 b/doc/man/cgcreate.1 deleted file mode 100644 index 6ec1b27c..00000000 --- a/doc/man/cgcreate.1 +++ /dev/null @@ -1,85 +0,0 @@ -.\" Written by Ivana Hutarova Varekova - -.TH CGCREATE 1 2009-03-15 "Linux" "libcgroup Manual" -.SH NAME -cgcreate \- create new cgroup(s) - -.SH SYNOPSIS -\fBcgcreate\fR [\fB-h\fR] [\fB-t\fR <\fItuid>:] -[\fB-a\fR <\fIagid>:] [\fB-f\fR mode] [\fB-d\fR mode] -[\fB-s\fR mode] \fB-g\fR <\fIcontrollers>: [\fB-g\fR ...] - -.SH DESCRIPTION -The command creates new cgroup(s) defined by the options -\fB-g\fR. - -.TP -.B -a : -defines the name of the user and the group which own the -rest of the defined control group’s files. These users are -allowed to set subsystem parameters and create subgroups. -The default value is the same as has the parent cgroup. - -.TP -.B -d, --dperm=mode -sets the permissions of a control groups directory. -The permissions needs to be specified as octal numbers e.g. -\fB-d 775\fR. - -.TP -.B -f, --fperm=mode -sets the permissions of the control groups parameters. -The permissions needs to be specified as octal numbers e.g. -\fB-f 775\fR. -The value is not used as given because the current owner's -permissions are used as an umask (so 777 will set group and -others permissions to the owners permissions). - -.TP -.B -g : -defines control groups to be added. -\fBcontrollers\fR is a list of controllers. Character "*" can be used -as a shortcut for "all mounted controllers". -\fBpath\fR is the relative path to control groups -in the given controllers list. This option can be specified -multiple times. - -.TP -.B -h, --help -display this help and exit - -.TP -.B -s, --tperm=mode -sets the permissions of the control group tasks file. -The permissions needs to be specified as octal numbers e.g. -\fB-s 775\fR. -The value is not used as given because the current owner's -permissions are used as an umask (so 777 will set group and -others permissions to the owners permissions). - -.TP -.B -t : -defines the name of the user and the group, which owns tasks -file of the defined control group. I.e. this user and members -of this group have write access to the file. -The default value is the same as has the parent cgroup. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH EXAMPLES -.TP -.B cgcreate -g *:student devices:teacher -create control group student in all mounted hierarchies and create -control group teacher in hierarchy containing controller devices. - - - - -.SH SEE ALSO -cgrules.conf (5) -cgexec (1) -cgclassify (1) \ No newline at end of file diff --git a/doc/man/cgdelete.1 b/doc/man/cgdelete.1 deleted file mode 100644 index 95722871..00000000 --- a/doc/man/cgdelete.1 +++ /dev/null @@ -1,45 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Jan Safranek - -.TH CGDELETE 1 2009-10-26 "Linux" "libcgroup Manual" -.SH NAME - -cgdelete \- remove control group(s) - -.SH SYNOPSIS -\fBcgdelete\fR [\fB-h\fR] [\fB-r\fR] [[\fB-g\fR] -<\fIcontrollers\fR>:\fI] ... - -.SH DESCRIPTION -The \fBcgdelete\fR -program removes all specified control groups. - -.TP -.B [-g] : -Defines the control group to delete. Multiple control groups may be -specified. -.B -g -is optional. - -.TP -.B -h, --help -Display this help and exit. - -.TP -.B -r, --recursive -Recursively remove all subgroups. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH EXAMPLES -.TP -.B cgdelete -g cpu,devices:/test -remove control group test from hierarchies containing cpu and device controllers - - -.SH SEE ALSO -cgcreate (1), lscgroup (1), cgclear (1) diff --git a/doc/man/cgexec.1 b/doc/man/cgexec.1 deleted file mode 100644 index cacbd3a0..00000000 --- a/doc/man/cgexec.1 +++ /dev/null @@ -1,96 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Varekova - -.TH CGEXEC 1 2009-03-15 "Linux" "libcgroup Manual" -.SH NAME - -cgexec \- run the task in given control groups - -.SH SYNOPSIS -\fBcgexec\fR [\fB-h\fR] [\fB-g\fR <\fIcontrollers>:] [--sticky] \fBcommand\fR [\fIarguments\fR] - -.SH DESCRIPTION -The \fBcgexec\fR -program executes the task \fBcommand\fR -with arguments \fBarguments\fR in the given control groups. - -.TP -.B -g : -defines the control groups in which the task will be run. -\fBcontrollers\fR is a list of controllers and -\fBpath\fR is the relative path to control groups -in the given controllers list. - -This flag can be used multiple times to -define multiple pairs of lists of controllers -and relative paths. -Instead of the list of all mounted controllers, -the wildcard \fBb"*b"\fR can be used. - -If this option is not used, -\fBcgexec\fR will automatically place the task in the right -cgroup based on \fB/etc/cgrules.conf\fR. - -If \fB/etc/cgrules.conf\fR configuration file is used, there can be used -template names. Then the control group name contains -a template in destination tag (see \fBcgrules.conf\fR (5)) -and if the cgroup does not exist in execution time, -it is created, based on \fB/etc/cgconfig.conf\fR specification. -If the specifications are not present the group is created with the default -kernel values. - -.TP -.B -h, --help -Display this help and exit. - -.TP -.B --sticky -If running the task \fBcommand\fR with this option, the daemon of -service cgred (cgrulesengd process) does not change both the task -of the \fBcommand\fR and the child tasks. Without this option, -the daemon does not change the task of the \fBcommand\fR but it -changes the child tasks to the right cgroup based on -\fB/etc/cgrules.conf\fR automatically. - -.LP - -.SH EXAMPLES - -.nf -.ft B -cgexec -g *:test1 ls -.ft R -.fi -runs command \fBls\fR in control group test1 -in all mounted controllers. - -.nf -.ft B -cgexec -g cpu,memory:test1 ls -l -.ft R -.fi -runs command \fBls -l\fR in control group test1 -in controllers cpu and memory. - -.nf -.ft B -cgexec -g cpu,memory:test1 -g swap:test2 ls -l -.ft R -.fi -runs command \fBls -l\fR in control group test1 -in controllers cpu and memory and control group -test2 in controller swap. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH FILES -.TP -.B /etc/cgrules.conf -default libcgroup configuration file - -.SH SEE ALSO -cgrules.conf (5) diff --git a/doc/man/cgget.1 b/doc/man/cgget.1 deleted file mode 100644 index 744a3296..00000000 --- a/doc/man/cgget.1 +++ /dev/null @@ -1,96 +0,0 @@ -.\" Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. -.\" Written by Jan Safranek - -.TH CGGET 1 2010-01-18 "Linux" "libcgroup Manual" -.SH NAME - -cgget \- print parameter(s) of given group(s) - -.SH SYNOPSIS -\fBcgget\fR [\fB-n\fR] [\fB-v\fR] [\fB-r\fR <\fIname\fR>] -[\fB-g\fR <\fIcontroller\fR>] [\fB-a\fR] <\fBpath\fR> ... -.br -\fBcgget\fR [\fB-n\fR] [\fB-v\fR] [\fB-r\fR <\fIname\fR>] -\fB-g\fR <\fIcontroller\fR>:<\fBpath\fR> ... - -.SH DESCRIPTION -Prints the parameter(s) of input cgroup(s). -If neither controller nor variable are specified, -the values of all possible variables are displayed. - -.TP -.B -is the name of the cgroup which should be read. -This parameter can be used multiple times. - -.TP -.B -a, --all -print the variables for all controllers which consist in the given cgroup - -.TP -.B -g -defines controllers whose values should be displayed. -This option can be used multiple times. - -.TP -.B -g : -defines control groups whose values should be displayed. -This option can be used multiple times. - -.TP -.B -h, --help -display help and exit - -.TP -.B -n -do not print headers, i.e. names of groups. - -.TP -.B -r, --variable -defines parameter to display. -This option can be used multiple times. - - -.TP -.B -v, --values-only -print only values, not parameter names. - -.SH EXAMPLES -.nf -$ cgget -r cpuset.cpus -r cpuset.mems first second -first: -cpuset.cpus=0-1 -cpuset.mems=0 - -second: -cpuset.cpus=0 -cpuset.mems=0 - -$ cgget -n -r cpuset.cpus -r cpuset.mems first second -cpuset.cpus=0-1 -cpuset.mems=0 -cpuset.cpus=0 -cpuset.mems=0 - -$ cgget -nv -r cpuset.cpus -r cpuset.mems first second -0-1 -0 -0 -0 - -$ cgget -n -g cpu / -cpu.rt_period_us=1000000 -cpu.rt_runtime_us=950000 -cpu.shares=1024 - -.fi - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH SEE ALSO -cgrules.conf (1), cgcreate (1), cgget (1) - diff --git a/doc/man/cgred.conf.5 b/doc/man/cgred.conf.5 deleted file mode 100644 index 1c0922f4..00000000 --- a/doc/man/cgred.conf.5 +++ /dev/null @@ -1,49 +0,0 @@ -.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Varekova . - -.TH CGRED.CONF 5 2009-03-16 "Linux" "libcgroup Manual" -.SH NAME -cgred.conf \- libcgroup configuration file -.SH DESCRIPTION -\fBcgred.conf\fR is cgred service configuration file. -In this file there could be defined several internal values. -Defining anything else in this file will cause the -CGroup Rules Daemon program to fail. -.TP - -\fBCONFIG_FILE\fR -specifies the configuration file for cgred service - -.TP -\fBLOG_FILE\fR -variable specifies the file to which logs will be written -(by default they are not sent to a file but to syslog) - -.TP -\fBNODAEMON\fR -if it is equal to "--nodamon" then -run cgred in non-daemon mode - -.TP -\fBLOG\fR -define the verbosity of logging. Accepted values are '-v', '-vv', '-q' -and '--nolog'. -.LP - - -.SH FILES -.LP -.PD .1v -.TP 20 -.B /etc/cgred.conf -.TP -default libcgroup configuration file -.PD . - -.SH SEE ALSO -cgrules.conf (5), -cgconfig.conf (5), cgrules.d (5) - - - - diff --git a/doc/man/cgrules.conf.5 b/doc/man/cgrules.conf.5 deleted file mode 100644 index 2d434e74..00000000 --- a/doc/man/cgrules.conf.5 +++ /dev/null @@ -1,165 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Varekova - -.TH CGRULES.CONF 5 2009-03-10 "Linux" "libcgroup Manual" -.SH NAME -cgrules.conf \- libcgroup configuration file -.SH DESCRIPTION -.B "cgrules.conf" -configuration file is used by -.B libcgroups -to define control groups to which a process belongs. - - -The file contains a list of rules which assign to a defined group/user a control -group in a subsystem (or control groups in subsystems). - -Rules have two formats: - -.in +4n -.nf - -.fi -.nf -: -.fi -.in - -Where: - -.I user -can be: -.nf - - a user name - - a group name with @group syntax - - the wildcard '*', for any user or group - - '%', which is equivalent to "ditto" (useful for - multi-line rules where different cgroups need to be - specified for various hierarchies for a single user) -.fi - -.I process name -is optional and it can be: -.nf - - a process name - - a full command path of a process -.fi - -.I controllers -can be: -.nf - - comma separated controller names (no spaces) or - - * (for all mounted controllers) -.fi - -.I destination -can be: -.nf - - path relative to the controller hierarchy (ex. pgrp1/gid1/uid1) - - following strings called "\fBtemplates\fR" and will get expanded - - %u username, uid if name resolving fails - %U uid - %g group name, gid if name resolving fails - %G gid - %p process name, pid if name not available - %P pid - - '\\' can be used to escape '%' -.fi -First rule which matches the criteria will be executed. - -Any text starting with '#' is considered as a start of comment line and is -ignored. - -If the -.I destination -contains -.B template -string, the control group can be created on-fly. In time when some process wants -to use the template rule which leads to control group (see -\fBcgexec\fR (1)) and the control group does not exist, the group is created. The -template control group parameters can be specified in -.B cgconfig.conf -configuration file. See (\fBcgconfig.conf\fR (5)). -If the template definition is not found there created group have default -kernel setting. - -To create a hierarchy of configuration files, use \fB/etc/cgrules.d\fR directory. - -.SH EXAMPLES -.nf -student devices /usergroup/students -.fi -Student's processes in the 'devices' subsystem belong to the control -group /usergroup/students. - -.nf -student:cp devices /usergroup/students/cp -.fi -When student executes 'cp' command, the processes in the 'devices' subsystem -belong to the control group /usergroup/students/cp. - -.nf -@admin * admingroup/ -.fi -Processes started by anybody from admin group no matter in what subsystem belong -to the control group admingroup/. - -.nf -peter cpu test1/ -% memory test2/ -.fi -The first line says Peter's task for cpu controller belongs to test1 control -group. The second one says Peter's tasks for memory controller belong to test2/ -control group. - -.nf -* * default/ -.fi -All processes in any subsystem belong to the control group default/. Since -the earliest matched rule is applied, it makes sense to have this line -at the end of the list. It will put a task which was not mentioned in the -previous rules to default/ control group. - -.nf -@students cpu,cpuacct students/%u -.fi -Processes in cpu and cpuacct subsystems started by anybody from students group -belong to group students/name. Where "name" is user name of owner of the -process. - - - -.SH FILES -.LP -.PD .1v -.TP 20 -.B /etc/cgrules.conf -.RS 6 -default libcgroup configuration file -.RE -.TP 20 -.B /etc/cgrules.d -.RS 6 -default libcgroup configuration files directory -.RE -.PD - - -.SH SEE ALSO -cgconfig.conf (5), cgclassify (1), cgred.conf (5), cgrules.d (5) - -.SH BUGS - - - - - - - - - - - - diff --git a/doc/man/cgrules.d.5 b/doc/man/cgrules.d.5 deleted file mode 100644 index 37717de4..00000000 --- a/doc/man/cgrules.d.5 +++ /dev/null @@ -1,50 +0,0 @@ -.\" Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. -.\" Written by Jan Chaloupka - -.TH CGRULES.D 5 2014-07-14 "Linux" "libcgroup Manual" -.SH NAME -cgrules.d \- libcgroup configuration files directory -.SH DESCRIPTION -.B "cgrules.d" -configuration files directory is used by -.B libcgroups -and contains additional configuration files with the same syntax as -\fBcgconfig.conf\fR (5). - -Files are parsed in an arbitrary order. -If the cache is disabled, the searching algorithm of \fBcgrulesengd\fR (8) -tries the first match. -If there are two rules which match the criteria for a given process, -and each rule is in a separate file, then there is no guarantee which one -is chosen. If you want to control the given order of the rules, put them -in one configuration file. - - -\fB/etc/cgconfig.conf\fR is parsed as the first file. After success, -all files from /etc/cgconfig.d are parsed as well (in an arbitrary order). -If some file from the directory ends up with a parsing error, -the process is stopped. With cache enabled, all successfully processed -rules -are kept in the cache. With cache disabled, -matching is stopped and ends with a 'not found' result. - -If \fB/etc/cgrules.d\fR is empty, \fBcgrulesengd\fR (8) acts -in a backwards compatibility mode. - -.SH FILES -.LP -.PD .1v -.TP 20 -.B /etc/cgrules.d -.RS 4 -default libcgroup configuration files directory -.RE -.B /etc/cgconfig.conf -.RS 4 -default libcgroup configuration file -.RE -.PD . - - -.SH SEE ALSO -cgconfig.conf (5), cgrulesengd (8) diff --git a/doc/man/cgrulesengd.8 b/doc/man/cgrulesengd.8 deleted file mode 100644 index cf456118..00000000 --- a/doc/man/cgrulesengd.8 +++ /dev/null @@ -1,84 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Jan Safranek . -.TH CGRULESENGD 8 2009-02-18 "Linux" "libcgroup Manual" -.SH NAME -cgrulesengd \- control group rules daemon - -.SH SYNOPSIS -\fBcgrulesengd\fR [options] - -.SH DESCRIPTION -\fBcgrulesengd\fR is a daemon, which distributes processes to control groups. When -any process changes its effective UID or GID, \fBcgrulesengd\fR inspects the list -of rules loaded from the \fIcgrules.conf\fR file and files in \fIcgrules.d\fR -(see \fBcgrules.d\fR (5) for potential conflicts) directory -and moves the process to the appropriate control group. - -The list of rules is read during the daemon startup and cached in the daemon's memory. -The daemon reloads the list of rules when it receives SIGUSR2 signal. -The daemon reloads the list of templates when it receives SIGUSR1 signal. - -The daemon opens a standard unix socket to receive 'sticky' requests from \fBcgexec\fR. - -.SH OPTIONS -.TP -.B -h|--help -Display help. -.TP -.B -f |--logfile= -Write log messages to the given log file. When '-' is used as , log messages -are written to the standard output. If '\fB-f\fR' and '\fB-s\fR' are used together, -the logs are sent to both destinations. - -.TP -.B -s[facility]|--syslog=[facility] -Write log messages to syslog. The default facility is DAEMON. If '\fB-f\fR' -and '\fB-s\fR' are used together, the logs are sent to both destinations. -.TP -.B -n|--nodaemon -Don't fork the daemon, stay in the foreground. -.TP -.B -v|--verbose -Display more log messages. This option can be used three times to enable more -verbose log messages. -.TP -.B -q|--quiet -Display less log messages. -.TP -.B -Q|--nolog -Disable logging. -.TP -.B -d|--debug -Equivalent to '-nvvvf -', i.e. don't fork the daemon, display all log messages and -write them to the standard output. -.TP -.B -u |--socket-user= -.B -g |--socket-group= -Set the owner of cgrulesengd socket. Assumes that \fBcgexec\fR runs with proper -suid permissions so it can write to the socket when \fBcgexec\fR --sticky is used. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH FILES -.TP -.B /etc/cgrules.conf -default libcgroup configuration file - -.TP -.B /etc/cgrules.d -default libcgroup configuration files directory - -.TP -.B /etc/cgconfig.conf -default templates file - -.TP -.B /etc/cgconfig.d -default templates directory - -.SH SEE ALSO -cgrules.conf (5), cgrules.d (5) diff --git a/doc/man/cgset.1 b/doc/man/cgset.1 deleted file mode 100644 index b05473f1..00000000 --- a/doc/man/cgset.1 +++ /dev/null @@ -1,51 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Hutarova Varekova - -.TH CGSET 1 2009-03-15 "Linux" "libcgroup Manual" -.SH NAME - -cgset \- set the parameters of given cgroup(s) - -.SH SYNOPSIS -\fBcgset\fR [\fB-r\fR <\fIname=value\fR>] <\fBcgroup_path\fR> ... -.br -\fBcgset\fR \fB--copy-from\fR <\fIsource_cgroup_path\fR> <\fBcgroup_path\fR> ... - -.SH DESCRIPTION -Set the parameters of input cgroups. - -.TP -.B -is the name of the cgroup which should be changed. -This parameter can be used multiple times. - -.TP -.B -r -defines the name of the file to set and -the value which should be written to that file. -This parameter can be used multiple times. - -.TP -.B --copy-from -defines the name of the cgroup whose parameters will be -copied to the input cgroup. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH EXAMPLES -.TP -.B cgset -r cpuset.cpus=0-1 student -set variable cpus in control group student (controller cpuset) to 0-1 - -.TP -.B cgset --copy-from group1/ group2/ -copy all parameters of group group1 to group group2 -(for all path where both cgroups are defined) - - -.SH SEE ALSO -cgrules.conf (1), cgcreate (1), cgget (1) diff --git a/doc/man/cgsnapshot.1 b/doc/man/cgsnapshot.1 deleted file mode 100644 index 48a038ed..00000000 --- a/doc/man/cgsnapshot.1 +++ /dev/null @@ -1,113 +0,0 @@ -.\" Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Hutarova Varekova - -.TH CGSNAPSHOT 1 2010-07-28 "Linux" "libcgroup Manual" -.SH NAME - -cgsnapshot \- generate the configuration file for given controllers - -.SH SYNOPSIS -\fBcgsnapshot\fR [\fB-h\fR] [\fB-s\fR] [\fB-t\fR] [\fB-b\fR \fIfile\fR] -[\fB-w\fR \fIfile\fR] [\fB-f\fR \fIoutput_file\fR] [\fBcontroller\fR] [...] - -.SH DESCRIPTION -\fBcgsnapshot\fR -generates the cgconfig compatible configuration file -for the given controllers. -If no controller is set, then -cgsnapshot shows all mounted hierarchies. -The output is in the same format as the -.B cgconfig.conf -configuration file. - -.TP -.B -b file -Display only variables from the blacklist. -The default location of the blacklist is -.B /etc/cgsnapshot_blacklist.conf. -This list contains all variables which should be ignored by the -.B cgsnapshot -. -If the variable is blacklisted, it will not be displayed. -If it is not present on the blacklist, the whitelist -is checked. - -.TP -.B -h, --help -display this help and exit - -.TP -.B -f, --file -Redirect the output to output_file - - -.TP -.B -s, --silent -Ignore all warnings - -.TP -.B -t, --strict -Do not display the variables which are not on the whitelist - - -.TP -.B -w file -Set the blacklist configuration file. -This list contains all variables which should be displayed by -.B cgsnapshot -. -If the variable is not blacklisted, the whitelist is checked. -If the variable is on the whitelist, it is displayed by -.B cgsnapshot -. -If the variable is not on the whitelist, -the variable is displayed and a warning message is produced. -By default the whitelist is not used. - -The warning message can be omitted using the -.B -s, --silent -flag. -If the -.B -t, --strict -flag is used, the variable which is not on the whitelist is -not displayed. - -.TP -.B controller -defines the controller whose hierarchies will be -output - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH FILES -.TP -.B /etc/cgsnapshot_blacklist.conf -default blacklist - -.TP -.B /etc/cgsnapshot_whitelist.conf -default whitelist - -.TP -.B /etc/cgconfig.conf -default libcgroup configuration file - -.SH EXAMPLES -.TP -.B cgsnapshot -s -f /etc/cgconfig.conf.cgsnapshot -create configuration file which contains all mounted controllers and all -control groups which are on the actual system - -.TP -.B cgsnapshot -s -f /etc/cgconfig.conf.cgsnapshot cpu -create configuration file which contains hierarchy containing cpu controller and all its -control groups on the actual system - - - -.SH SEE ALSO -cgconfig.conf (5) diff --git a/doc/man/lscgroup.1 b/doc/man/lscgroup.1 deleted file mode 100644 index 124379e0..00000000 --- a/doc/man/lscgroup.1 +++ /dev/null @@ -1,46 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Hutarova Varekova - -.TH LSCGROUP 1 2009-11-05 "Linux" "libcgroup Manual" -.SH NAME - -lscgroup \- list all cgroups - -.SH SYNOPSIS -\fBlscgroup\fR [[\fB-g\fR] <\fIcontrollers>:] [...] -.br -\fBlscgroup\fR [\fB-h|--help\fR] - -.SH DESCRIPTION -List all/chosen cgroups. - -.TP -.B : -defines the control groups whose subgroups will be shown. -If this parameter is not used, the command will -list all existing cgroups. - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.SH EXAMPLES -.TP -.B lscgroup -g cpu:/ -list all cgroups which are in hierarchy containing cpu controller - -.TP -.B lscgroup -g cpu:/student -list all cgroups which are in hierarchy containing cpu controller -in subgroup student - -.TP -.B lscgroup -list all cgroups which in all hierarchies - - -.SH SEE ALSO -lssubsys (1), cgcreate (1), cgdelete (1), -cgconfig.conf (5) diff --git a/doc/man/lssubsys.1 b/doc/man/lssubsys.1 deleted file mode 100644 index 790c6271..00000000 --- a/doc/man/lssubsys.1 +++ /dev/null @@ -1,97 +0,0 @@ -.\" Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -.\" Written by Ivana Hutarova Varekova - -.TH LSSUBSYS 1 2009-11-05 "Linux" "libcgroup Manual" -.SH NAME - -lssubsys \- list hierarchies containing given subsystem - -.SH SYNOPSIS -\fBlssubsys\fR [\fB-m|--mount-points\fR] [\fB-M|--all-mount-points\fR] -[\fIcontroller\fR] [...] -.br -\fBlssubsys\fR [\fB-m|--mount-points\fR] [\fB-M|--all-mount-points\fR] -[\fB-i|--hierarchies\fR] [\fB-a|--all\fR] -.br -\fBlssubsys\fR [\fB-h|--help\fR] - -.SH DESCRIPTION -\fBlssubsys\fR list the hierarchies containing -the given subsystem(s). If no subsystem is defined, it -displays all mounted hierarchies. - -.TP -.B controller -defines the subsystem whose hierarchy is shown. -If this parameter is not used, the command will -list all mounted subsystems. - -.TP -.B -m, --mount-points -Display mount points. Only the first mount points of shown hierarchies are displayed. - -.TP -.B -M, --all-mount-points -Display mount points. All mount points of shown hierarchies are displayed, each on -separate line. - -.TP -.B -a, --all -Display all subsystems (including unmounted ones). - -.TP -.B -i, --hierarchies -Display the attached hierarchy number if the subsystem is in a hierarchy. -If the option -.B -m -is also used, the hierarchy number is shown only for unmounted hierarchies. - -.TP -.B -h, --help -Display help and exit. - -.SH EXAMPLE -The command -.B lssubsys -am -lists all subsystems which are present in the system, -mounted ones will be shown with their mount point: -.RS -.nf -$ lssubsys -am -ns -cpuset -cpu,devices -cpuacct /cgroup/cpuacct -memory /cgroup/memory -freezer /cgroup/freezer -net_cls /cgroup/net_cls -.fi -.RE -.LP -The command -.B lssubsys -ami -lists all subsystems which are present in the system, -mounted subsystems are listed with their mount points, -unmounted ones which are in a hierarchy are listed with their hierarchy number: -.RS -.nf -$ lssubsys -ami -ns -cpuset 5 -cpu,devices 6 -cpuacct /cgroup/cpuacct -memory /cgroup/memory -freezer /cgroup/freezer -net_cls /cgroup/net_cls -.fi - -.SH ENVIRONMENT VARIABLES -.TP -.B CGROUP_LOGLEVEL -controls verbosity of the tool. Allowed values are \fBDEBUG\fR, -\fBINFO\fR, \fBWARNING\fR or \fBERROR\fR. - -.RE -.SH SEE ALSO -lscgroup (1), cgcreate (1), cgdelete (1), -cgconfig.conf (5) diff --git a/googletest b/googletest deleted file mode 160000 index 8ffb7e5c..00000000 --- a/googletest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8ffb7e5c88b20a297a2e786c480556467496463b diff --git a/include/Makefile.am b/include/Makefile.am deleted file mode 100644 index 752a624c..00000000 --- a/include/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -# Using 'nobase_', we what groups.h in /usr/include/libcgroup/ directory -nobase_include_HEADERS = libcgroup.h libcgroup/error.h libcgroup/init.h libcgroup/groups.h libcgroup/tasks.h libcgroup/iterators.h libcgroup/config.h libcgroup/log.h diff --git a/include/libcgroup.h b/include/libcgroup.h deleted file mode 100644 index 1c7d409a..00000000 --- a/include/libcgroup.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright IBM Corporation. 2007 - * - * Author: Balbir Singh - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef _LIBCGROUP_H -#define _LIBCGROUP_H - -#define _LIBCGROUP_H_INSIDE - -#include -#include -#include -#include -#include -#include -#include - -#undef _LIBCGROUP_H_INSIDE - -/*! \mainpage libcgroup - * - * \section intro_sec Introduction - * - * @c libcgroup is a library that abstracts the control group file system in Linux. - * It comes with various command-line tools and configuration files, see - * their man pages for details. - * - * This documentation provides description of @c libcgroup API. Read following - * sections, preferably in this order: - * -# @ref group_init "Initialization" - * -# @ref group_groups "Control Groups" - * -# @ref group_iterators "Iterators" - * -# @ref group_tasks "Manipulation with tasks" - * -# @ref group_config "Configuration" - * -# @ref group_errors "Error Handling" - */ - -#endif /* _LIBCGROUP_H */ diff --git a/include/libcgroup/config.h b/include/libcgroup/config.h deleted file mode 100644 index 9aaa3903..00000000 --- a/include/libcgroup/config.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef _LIBCGROUP_CONFIG_H -#define _LIBCGROUP_CONFIG_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#ifndef SWIG -#include -#endif - -__BEGIN_DECLS - -/** - * @defgroup group_config 5. Configuration - * @{ - * - * @name Configuration file - * @{ - * - * @c libcgroup can mount and create control groups and set their parameters as - * specified in a configuration file. - * - * @todo add this description?: These functions are mostly intended - * to be used by internal @c libcgroup tools, however they are fully supported - * and applications can benefit from them. - */ - -/** - * Load configuration file and mount and create control groups described there. - * See cgconfig.conf man page for format of the file. - * @param pathname Name of the configuration file to load. - */ -int cgroup_config_load_config(const char *pathname); - -/** - * Delete all control groups and unmount all hierarchies. - */ -int cgroup_unload_cgroups(void); - -/** - * Delete all cgroups and unmount all mount points defined in specified config - * file. - * - * The groups are either removed recursively or only the empty ones, based - * on given flags. Mount point are always umounted only if they are empty, - * regardless of any flags. - * - * The groups are sorted before they are removed, so the removal of empty ones - * actually works (i.e. subgroups are removed first). - * - * @param pathname Name of the configuration file to unload. - * @param flags Combination of CGFLAG_DELETE_* flags, which indicate what and - * how to delete. - */ -int cgroup_config_unload_config(const char *pathname, int flags); - -/** - * Sets default permissions of groups created by subsequent - * cgroup_config_load_config() calls. If a config file contains a 'default {}' - * section, the default permissions from the config file is then used. - * - * Use cgroup_new_cgroup() to create a dummy group and cgroup_set_uid_gid() and - * cgroup_set_permissions() to set its permissions. Use NO_UID_GID instead of - * GID/UID and NO_PERMS instead of file/directory permissions to let kernel - * decide the default permissions where you don't want specific user and/or - * permissions. Kernel then uses current user/group and permissions from umask - * then. - * - * @param new_default New default permissions from this group are copied to - * libcgroup internal structures. I.e., this group can be freed immediatelly - * after this function returns. - */ -int cgroup_config_set_default(struct cgroup *new_default); - -/** - * Initializes the templates cache and load it from file pathname. - */ -int cgroup_init_templates_cache(char *pathname); - -/** - * Reloads the templates list from file pathname. - */ -int cgroup_reload_cached_templates(char *pathname); - -/** - * Load the templates cache from files. Before calling this function, - * cgroup_templates_cache_set_source_files has to be called first. - * @param file_index index of file which was unable to be parsed - * @return 0 on success, > 0 on error - */ -int cgroup_load_templates_cache_from_files(int *file_index); - -/** - * Setting source files of templates. This function has to be called before - * any call of cgroup_load_templates_cache_from_files. - * @param tmpl_files - */ -struct cgroup_string_list; -void cgroup_templates_cache_set_source_files( - struct cgroup_string_list *tmpl_files); - -/** - * Physically create a new control group in kernel, based on given control - * group template and configuration file. If given template is not set in - * configuration file, then the procedure works create the control group - * using cgroup_create_cgroup() function - * - * Templates are loaded using cgroup_load_templates_cache_from_files - * function, which must be preceded by cgroup_templates_cache_set_source_files - * call. - * - * The flags can alter the behavior of this function: - * CGFLAG_USE_TEMPLATE_CACHE: Use cached templates instead of - * parsing the config file - * - * @param pathname Name of the configuration file with template definitions - * @param cgroup Wanted control group - contains substitute name and wanted - * controllers. - * @param template_name Template name used for cgroup setting - * @param flags Bit flags to change the behavior - */ -int cgroup_config_create_template_group( - struct cgroup *cgroup, char *template_name, - int flags); - -/** - * @} - * @} - */ -__END_DECLS - -#endif /*_LIBCGROUP_CONFIG_H*/ diff --git a/include/libcgroup/error.h b/include/libcgroup/error.h deleted file mode 100644 index 1dfdde9d..00000000 --- a/include/libcgroup/error.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _LIBCGROUP_ERROR_H -#define _LIBCGROUP_ERROR_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#ifndef SWIG -#include -#endif - -__BEGIN_DECLS - -/** - * @defgroup group_errors 6. Error handling - * @{ - * - * @name Error handling - * @{ - * Unless states otherwise in documentation of a function, all functions - * return @c int, which is zero (0) when the function succeeds, and positive - * number if the function fails. - * - * The returned integer is one of the ECG* values described below. Value - * #ECGOTHER means that the error was caused by underlying OS and the real - * cause can be found by calling cgroup_get_last_errno(). - */ - -enum { - ECGROUPNOTCOMPILED = 50000, - ECGROUPNOTMOUNTED, - ECGROUPNOTEXIST, - ECGROUPNOTCREATED, - ECGROUPSUBSYSNOTMOUNTED, - ECGROUPNOTOWNER, - /** Controllers bound to different mount points */ - ECGROUPMULTIMOUNTED, - /* This is the stock error. Default error. @todo really? */ - ECGROUPNOTALLOWED, - ECGMAXVALUESEXCEEDED, - ECGCONTROLLEREXISTS, - ECGVALUEEXISTS, - ECGINVAL, - ECGCONTROLLERCREATEFAILED, - ECGFAIL, - ECGROUPNOTINITIALIZED, - ECGROUPVALUENOTEXIST, - /** - * Represents error coming from other libraries like glibc. @c libcgroup - * users need to check cgroup_get_last_errno() upon encountering this - * error. - */ - ECGOTHER, - ECGROUPNOTEQUAL, - ECGCONTROLLERNOTEQUAL, - /** Failed to parse rules configuration file. */ - ECGROUPPARSEFAIL, - /** Rules list does not exist. */ - ECGROUPNORULES, - ECGMOUNTFAIL, - /** - * Not an real error, it just indicates that iterator has come to end - * of sequence and no more items are left. - */ - ECGEOF = 50023, - /** Failed to parse config file (cgconfig.conf). */ - ECGCONFIGPARSEFAIL, - ECGNAMESPACEPATHS, - ECGNAMESPACECONTROLLER, - ECGMOUNTNAMESPACE, - ECGROUPUNSUPP, - ECGCANTSETVALUE, - /** Removing of a group failed because it was not empty. */ - ECGNONEMPTY, -}; - -/** - * Legacy definition of ECGRULESPARSEFAIL error code. - */ -#define ECGRULESPARSEFAIL ECGROUPPARSEFAIL - -/** - * Format error code to a human-readable English string. No internationalization - * is currently done. Returned pointer leads to @c libcgroup memory and - * must not be freed nor modified. The memory is rewritten by subsequent - * call to this function. - * @param code Error code for which the corresponding error string is - * returned. When #ECGOTHER is used, text with glibc's description of - * cgroup_get_last_errno() value is returned. - */ -const char *cgroup_strerror(int code); - -/** - * Return last errno, which caused ECGOTHER error. - */ -int cgroup_get_last_errno(void); - -/** - * @} - * @} - */ -__END_DECLS - -#endif /* _LIBCGROUP_INIT_H */ diff --git a/include/libcgroup/groups.h b/include/libcgroup/groups.h deleted file mode 100644 index 201558f6..00000000 --- a/include/libcgroup/groups.h +++ /dev/null @@ -1,592 +0,0 @@ -#ifndef _LIBCGROUP_GROUPS_H -#define _LIBCGROUP_GROUPS_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#ifndef SWIG -#include -#include -#include -#endif - -__BEGIN_DECLS - -/** - * Flags for cgroup_delete_cgroup_ext(). - */ -enum cgroup_delete_flag { - /** - * Ignore errors caused by migration of tasks to parent group. - */ - CGFLAG_DELETE_IGNORE_MIGRATION = 1, - - /** - * Recursively delete all child groups. - */ - CGFLAG_DELETE_RECURSIVE = 2, - - /** - * Delete the cgroup only if it is empty, i.e. it has no subgroups and - * no processes inside. This flag cannot be used with - * CGFLAG_DELETE_RECURSIVE. - */ - CGFLAG_DELETE_EMPTY_ONLY = 4, -}; - -/** - * @defgroup group_groups 2. Group manipulation API - * @{ - * - * @name Basic infrastructure - * @{ - * struct cgroup* is the heart of @c libcgroup API. - * The structure is opaque to applications, all access to the structure is - * through appropriate functions. - * - * The most important information is that one struct cgroup* can - * represent zero, one or more real control groups in kernel. - * The struct cgroup* is identified by name of the group, which must be - * set by cgroup_new_cgroup(). Multiple controllers (aka subsystems) can be - * attached to one struct cgroup* using cgroup_add_controller(). These - * controllers can belong to different hierarchies. - * - * This approach is different to the one in the Linux kernel - a control group - * must be part of exactly one hierarchy there. In @c libcgroup, a group can be - * part of multiple hierarchies, as long as the group name is the same. - * - * @par Example: - * Let there be following control groups: - * @code - * cpu,cpuacct:/ - * cpu,cpuacct:/foo - * cpu,cpuacct:/bar - * freezer:/ - * freezer:/foo - * @endcode - * I.e. there is @c cpu and @c cpuacct controller mounted together in one - * hierarchy, with @c foo and @c bar groups. In addition, @c freezer is - * mounted as separate hierarchy, with only one @c foo group. - * - * @par - * Following code creates struct cgroup* structure, which represents - * one group cpu,cpuacct:/foo: - * @code - * struct cgroup *foo = cgroup_new_cgroup("foo"); - * cgroup_add_controller(foo, "cpu"); - * @endcode - * Now, you can call e.g. cgroup_delete_cgroup() and the group is deleted from - * the hierarchy. You can note that it's enough to add only one controller to - * the group to fully identify a group in cpu,cpuacct hierarchy. - * - * @par - * Following code creates struct cgroup* structure, which represents - * @b two groups, cpu,cpuacct:/foo and freezer:/foo: - * @code - * struct cgroup *foo = cgroup_new_cgroup("foo"); - * cgroup_add_controller(foo, "cpu"); - * cgroup_add_controller(foo, "freezer"); - * @endcode - * Now, if you call e.g. cgroup_delete_cgroup(), the group gets deleted from - * @b both hierarchies. - * - * @todo add some propaganda what's so great on this approach... I personally - * think it is broken and confusing (see TODOs below). - * - * Following functions are provided to create/destroy various libcgroup - * structures. Please note that none of these functions actually create or - * delete a cgroup in kernel! - */ - -/** - * @struct cgroup - * - * Structure describing one or more control groups. The structure is opaque to - * applications. - */ -struct cgroup; - -/** - * @struct cgroup_controller - * Structure describing a controller attached to one struct @c cgroup, including - * parameters of the group and their values. The structure is opaque to - * applications. - * @see groups - */ -struct cgroup_controller; - -/** - * Uninitialized file/directory permissions used for task/control files. - */ -#define NO_PERMS (-1U) - -/** - * Uninitialized UID/GID used for task/control files. - */ -#define NO_UID_GID (-1U) - -/** - * Allocate new cgroup structure. This function itself does not create new - * control group in kernel, only new struct cgroup inside libcgroup! - * - * @param name Path to the group, relative from root group. Use @c "/" or @c "." - * for the root group itself and @c "/foo/bar/baz" or @c "foo/bar/baz" for - * subgroups. - * @todo suggest one preferred way, either "/foo" or "foo". - * @returns Created group or NULL on error. - */ -struct cgroup *cgroup_new_cgroup(const char *name); - -/** - * Attach new controller to cgroup. This function just modifies internal - * libcgroup structure, not the kernel control group. - * - * @param cgroup - * @param name Name of the controller, e.g. "freezer". - * @return Created controller or NULL on error. - */ -struct cgroup_controller *cgroup_add_controller(struct cgroup *cgroup, - const char *name); - -/** - * Attach all mounted controllers to given cgroup. This function just modifies - * internal libcgroup structure, not the kernel control group. - * - * @param cgroup - * @return zero or error number - */ -int cgroup_add_all_controllers(struct cgroup *cgroup); - - -/** - * Return appropriate controller from given group. - * The controller must be added before using cgroup_add_controller() or loaded - * from kernel using cgroup_get_cgroup(). - * @param cgroup - * @param name Name of the controller, e.g. "freezer". - */ -struct cgroup_controller *cgroup_get_controller(struct cgroup *cgroup, - const char *name); - -/** - * Free internal @c cgroup structure. This function frees also all controllers - * attached to the @c cgroup, including all parameters and their values. - * @param cgroup - */ -void cgroup_free(struct cgroup **cgroup); - -/** - * Free internal list of controllers from the group. - * @todo should this function be public??? - * @param cgroup - */ -void cgroup_free_controllers(struct cgroup *cgroup); - - -/** - * @} - * @name Group manipulation API - * Using following functions you can create and remove control groups and - * change their parameters. - * @note All access to kernel is through previously mounted cgroup filesystems. - * @c libcgroup does not mount/unmount anything for you. - * @{ - */ - -/** - * Physically create a control group in kernel. The group is created in all - * hierarchies, which cover controllers added by cgroup_add_controller(). - * All parameters set by cgroup_add_value_* functions are written. - * The created groups has owner which was set by cgroup_set_uid_gid() and - * permissions set by cgroup_set_permissions. - * @param cgroup - * @param ignore_ownership When nozero, all errors are ignored when setting - * owner of the group and/or its tasks file. - * @todo what is ignore_ownership good for? - * @retval #ECGROUPNOTEQUAL if not all specified controller parameters - * were successfully set. - */ -int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership); - -/** - * Physically create new control group in kernel, with all parameters and values - * copied from its parent group. The group is created in all hierarchies, where - * the parent group exists. I.e. following code creates subgroup in all - * hierarchies, because all of them have root (=parent) group. - * @code - * struct cgroup *foo = cgroup_new_cgroup("foo"); - * cgroup_create_cgroup_from_parent(foo, 0); - * @endcode - * @todo what is this good for? Why the list of controllers added by - * cgroup_add_controller() is not used, like in cgroup_create_cgroup()? I can't - * crate subgroup of root group in just one hierarchy with this function! - * - * @param cgroup The cgroup to create. Only it's name is used, everything else - * is discarded. - * @param ignore_ownership When nozero, all errors are ignored when setting - * owner of the group and/or its tasks file. - * @todo what is ignore_ownership good for? - * @retval #ECGROUPNOTEQUAL if not all inherited controller parameters - * were successfully set (this is expected). - */ -int cgroup_create_cgroup_from_parent(struct cgroup *cgroup, - int ignore_ownership); - -/** - * Physically modify a control group in kernel. All parameters added by - * cgroup_add_value_ or cgroup_set_value_ are written. - * Currently it's not possible to change and owner of a group. - * - * @param cgroup - */ -int cgroup_modify_cgroup(struct cgroup *cgroup); - -/** - * Physically remove a control group from kernel. The group is removed from - * all hierarchies, which cover controllers added by cgroup_add_controller() - * or cgroup_get_cgroup(). All tasks inside the group are automatically moved - * to parent group. - * - * The group being removed must be empty, i.e. without subgroups. Use - * cgroup_delete_cgroup_ext() for recursive delete. - * - * @param cgroup - * @param ignore_migration When nozero, all errors are ignored when migrating - * tasks from the group to the parent group. - * @todo what is ignore_migration good for? rmdir() will fail if tasks were not moved. - */ -int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration); - -/** - * Physically remove a control group from kernel. - * All tasks are automatically moved to parent group. - * If #CGFLAG_DELETE_IGNORE_MIGRATION flag is used, the errors that occurred - * during the task movement are ignored. - * #CGFLAG_DELETE_RECURSIVE flag specifies that all subgroups should be removed - * too. If root group is being removed with this flag specified, all subgroups - * are removed but the root group itself is left undeleted. - * @see cgroup_delete_flag. - * - * @param cgroup - * @param flags Combination of CGFLAG_DELETE_* flags, which indicate what and - * how to delete. - */ -int cgroup_delete_cgroup_ext(struct cgroup *cgroup, int flags); - - -/** - * @} - * @name Other functions - * @{ - * Helper functions to manipulate with control groups. - */ - -/** - * Read all information regarding the group from kernel. - * Based on name of the group, list of controllers and all parameters and their - * values are read from all hierarchies, where a group with given name exists. - * All existing controllers are replaced. I.e. following code will fill @c root - * with controllers from all hierarchies, because the root group is available in - * all of them. - * @code - * struct cgroup *root = cgroup_new_cgroup("/"); - * cgroup_get_cgroup(root); - * @endcode - * - * @todo what is this function good for? Why is not considered only the list of - * controllers attached by cgroup_add_controller()? What owners will return - * cgroup_get_uid_gid() if the group is in multiple hierarchies, each with - * different owner of tasks file? - * - * @param cgroup The cgroup to load. Only it's name is used, everything else - * is replaced. - */ -int cgroup_get_cgroup(struct cgroup *cgroup); - -/** - * Copy all controllers, their parameters and values. Group name, permissions - * and ownerships are not coppied. All existing controllers - * in the source group are discarded. - * - * @param dst Destination group. - * @param src Source group. - */ -int cgroup_copy_cgroup(struct cgroup *dst, struct cgroup *src); - -/** - * Compare names, owners, controllers, parameters and values of two groups. - * - * @param cgroup_a - * @param cgroup_b - * - * @retval 0 if the groups are the same. - * @retval #ECGROUPNOTEQUAL if the groups are not the same. - * @retval #ECGCONTROLLERNOTEQUAL if the only difference are controllers, - * parameters or their values. - */ -int cgroup_compare_cgroup(struct cgroup *cgroup_a, struct cgroup *cgroup_b); - - -/** - * Compare names, parameters and values of two controllers. - * - * @param cgca - * @param cgcb - * - * @retval 0 if the controllers are the same. - * @retval #ECGCONTROLLERNOTEQUAL if the controllers are not equal. - */ -int cgroup_compare_controllers(struct cgroup_controller *cgca, - struct cgroup_controller *cgcb); - -/** - * Set owner of the group control files and the @c tasks file. This function - * modifies only @c libcgroup internal @c cgroup structure, use - * cgroup_create_cgroup() afterwards to create the group with given owners. - * - * @param cgroup - * @param tasks_uid UID of the owner of group's @c tasks file. - * @param tasks_gid GID of the owner of group's @c tasks file. - * @param control_uid UID of the owner of group's control files (i.e. - * parameters). - * @param control_gid GID of the owner of group's control files (i.e. - * parameters). - */ -int cgroup_set_uid_gid(struct cgroup *cgroup, uid_t tasks_uid, gid_t tasks_gid, - uid_t control_uid, gid_t control_gid); - -/** - * Return owners of the group's @c tasks file and control files. - * The data is read from @c libcgroup internal @c cgroup structure, use - * cgroup_set_uid_gid() or cgroup_get_cgroup() to fill it. - */ -int cgroup_get_uid_gid(struct cgroup *cgroup, uid_t *tasks_uid, - gid_t *tasks_gid, uid_t *control_uid, gid_t *control_gid); - -/** - * Stores given file permissions of the group's control and tasks files - * into the @c cgroup data structure. Use NO_PERMS if permissions shouldn't - * be changed or a value which applicable to chmod(2). Please note that - * the given permissions are masked with the file owner's permissions. - * For example if a control file has permissions 640 and control_fperm is - * 471 the result will be 460. - * @param cgroup - * @param control_dperm Directory permission for the group. - * @param control_fperm File permission for the control files. - * @param task_fperm File permissions for task file. - */ -void cgroup_set_permissions(struct cgroup *cgroup, - mode_t control_dperm, mode_t control_fperm, - mode_t task_fperm); - -/** - * @} - * @name Group parameters - * These are functions can read or modify parameter of a group. - * @note All these functions read/write parameters to @c libcgorup internal - * structures. Use cgroup_get_cgroup() to load parameters from kernel to these - * internal structures and cgroup_modify_cgroup() or cgroup_create_cgroup() to - * write changes to kernel. - * @{ - */ - -/** - * Add parameter and its value to internal @c libcgroup structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - * - */ -int cgroup_add_value_string(struct cgroup_controller *controller, - const char *name, const char *value); -/** - * Add parameter and its value to internal @c libcgroup structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * Content of the value is copied to internal structures and is not needed - * after return from the function. - * - * @param controller - * @param name Name of the parameter. - * @param value - * - */ -int cgroup_add_value_int64(struct cgroup_controller *controller, - const char *name, int64_t value); -/** - * Add parameter and its value to internal @c libcgroup structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - * - */ -int cgroup_add_value_uint64(struct cgroup_controller *controller, - const char *name, u_int64_t value); -/** - * Add parameter and its value to internal @c libcgroup structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - * - */ -int cgroup_add_value_bool(struct cgroup_controller *controller, - const char *name, bool value); - -/** - * Read a parameter value from @c libcgroup internal structures. - * Use @c cgroup_get_cgroup() to fill these structures with data from kernel. - * It's up to the caller to free returned value. - * - * This function works only for 'short' parameters. Use - * cgroup_read_stats_begin(), cgroup_read_stats_next() and - * cgroup_read_stats_end() to read @c stats parameter, which can be longer - * than libcgroup's internal buffers. - * @todo rephrase, it's too vague... How big is the buffer actually? - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_get_value_string(struct cgroup_controller *controller, - const char *name, char **value); -/** - * Read a parameter value from @c libcgroup internal structures. - * Use @c cgroup_get_cgroup() to fill these structures with data from kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_get_value_int64(struct cgroup_controller *controller, - const char *name, int64_t *value); -/** - * Read a parameter value from @c libcgroup internal structures. - * Use @c cgroup_get_cgroup() to fill these structures with data from kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_get_value_uint64(struct cgroup_controller *controller, - const char *name, u_int64_t *value); -/** - * Read a parameter value from @c libcgroup internal structures. - * Use @c cgroup_get_cgroup() to fill these structures with data from kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_get_value_bool(struct cgroup_controller *controller, - const char *name, bool *value); - -/** - * Set a parameter value in @c libcgroup internal structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_set_value_string(struct cgroup_controller *controller, - const char *name, const char *value); -/** - * Set a parameter value in @c libcgroup internal structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * Content of the value is copied to internal structures and is not needed - * after return from the function. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_set_value_int64(struct cgroup_controller *controller, - const char *name, int64_t value); -/** - * Set a parameter value in @c libcgroup internal structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_set_value_uint64(struct cgroup_controller *controller, - const char *name, u_int64_t value); -/** - * Set a parameter value in @c libcgroup internal structures. - * Use cgroup_modify_cgroup() or cgroup_create_cgroup() to write it to kernel. - * - * @param controller - * @param name Name of the parameter. - * @param value - */ -int cgroup_set_value_bool(struct cgroup_controller *controller, - const char *name, bool value); -/** - * Return the number of variables for the specified controller in @c libcgroup - * internal structures. Use cgroup_get_cgroup() to fill these structures with - * data from kernel. Use this function together with cgroup_get_value_name() - * to list all parameters of a group. - * - * @param controller - * @return Count of the parameters or -1 on error. - */ -int cgroup_get_value_name_count(struct cgroup_controller *controller); - -/** - * Return the name of parameter of controller at given index. - * The index goes from 0 to cgroup_get_value_name_count()-1. - * Use this function to list all parameter of the controller. - * - * @note The returned value is pointer to internal @c libcgroup structure, - * do not free it. - * - * @param controller - * @param index Index of the parameter. - * @return Name of the parameter. - */ -char *cgroup_get_value_name(struct cgroup_controller *controller, int index); - -/** - * Get the list of process in a cgroup. This list is guaranteed to - * be sorted. It is not necessary that it is unique. - * @param name The name of the cgroup - * @param controller The name of the controller - * @param pids The list of pids. Should be uninitialized when passed - * to the API. Should be freed by the caller using free. - * @param size The size of the pids array returned by the API. - */ -int cgroup_get_procs(char *name, char *controller, pid_t **pids, int *size); - -/** - * Change permission of files and directories of given group - * @param cgroup The cgroup which permissions should be changed - * @param dir_mode The permission mode of group directory - * @param dirm_change Denotes whether the directory change should be done - * @param file_mode The permission mode of group files - * @param filem_change Denotes whether the directory change should be done - */ -int cg_chmod_recursive(struct cgroup *cgroup, mode_t dir_mode, - int dirm_change, mode_t file_mode, int filem_change); - -/** - * Get the name of the cgroup from a given cgroup - * @param cgroup The cgroup whose name is needed - */ -char *cgroup_get_cgroup_name(struct cgroup *cgroup); - -/** - * @} - * @} - */ - - -__END_DECLS - -#endif /* _LIBCGROUP_GROUPS_H */ diff --git a/include/libcgroup/init.h b/include/libcgroup/init.h deleted file mode 100644 index 5150f2fc..00000000 --- a/include/libcgroup/init.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _LIBCGROUP_INIT_H -#define _LIBCGROUP_INIT_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#ifndef SWIG -#include -#endif - -__BEGIN_DECLS - -/** - * @defgroup group_init 1. Initialization - * @{ - * - * @name Initialization - * @{ - * Application must initialize @c libcgroup using cgroup_init() before any - * other @c libcgroup function can be called. @c libcgroup caches information - * about mounted hierarchies (just what's mounted where, not the control groups - * themselves) at this time. There is currently no way to refresh this cache, - * i.e. all subsequent mounts/remounts/unmounts are not reflected in this cache - * and @c libcgroup may produce unexpected results. - * - * In addition, there is no way how to clean the cache on application exit. - * - * @todo this is very bad... There should be at least way how to refresh the - * cache and/or an option to refresh it automatically (does kernel provide - * any indication, when a filesystem is mounted/unmounted?). Dtto the cleanup - * on exit. - */ - -/** - * Initialize libcgroup. Information about mounted hierarchies are examined - * and cached internally (just what's mounted where, not the groups themselves). - * - * If the cgroup logging was not set using cgroup_set_logger() or - * cgroup_set_default_logger() before calling cgroup_init(), the default logger - * is automatically set, logging CGROUP_LOG_ERROR messages. - */ -int cgroup_init(void); - -/** - * Returns path where is mounted given controller. Applications should rely on - * @c libcgroup API and not call this function directly. - * Only the first mount point is returned, use - * cgroup_get_subsys_mount_point_begin(), cgroup_get_subsys_mount_point_next() - * and cgroup_get_subsys_mount_point_end() to get all of them. - * @param controller Name of the controller - * @param mount_point The string where the mount point location is stored. - * Please note, the caller must free the mount_point. - */ -int cgroup_get_subsys_mount_point(const char *controller, char **mount_point); - -/** - * @} - * @} - */ -__END_DECLS - -#endif /* _LIBCGROUP_INIT_H */ diff --git a/include/libcgroup/iterators.h b/include/libcgroup/iterators.h deleted file mode 100644 index c6d453d6..00000000 --- a/include/libcgroup/iterators.h +++ /dev/null @@ -1,428 +0,0 @@ -#ifndef _LIBCGROUP_ITERATORS_H -#define _LIBCGROUP_ITERATORS_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#ifndef SWIG -#include -#include -#include -#endif - -__BEGIN_DECLS - -/** - * @defgroup group_iterators 3. Iterators - * @{ - * So-called iterators are a code pattern to retrieve various data from - * libcgroup in distinct chunks, for example when an application needs to read - * list of groups in a hierarchy, it uses iterator to get one group at a time. - * Iterator is opaque to the application, the application sees only - * void* handle pointer, which is managed internally by @c libcgroup. - * Each iterator provides at least these functions: - * - int iterator_name_begin(void **handle, my_type *item) - * - Initialize the iterator, store pointer to it into the @c handle. - * - Return the first element in the iterator, let's say it's @c my_type. - * - Return @c 0, if the operation succeeded. - * - Return #ECGEOF, if the operation succeeded, but the iterator is empty. - * The value of @c item is undefined in this case. - * - Return any other error code on error. - * - int iterator_name_next(void **handle, my_type *item) - * - Advance to next element in the iterator and return it. - * - Return @c 0, if the operation succeeded. - * - Return #ECGEOF, if there is no item to advance to, i.e. the iterator - * is already at its end. The value of @c item is undefined in this case. - * - Return any other error code on error. - * - void iterator_name_end(void **handle) - * - Free any data associated with the iterator. This function must be - * called even when iterator_name_begin() fails. - * - * @todo not all iterators follow this pattern, e.g. cgroup_walk_tree_begin() - * can result both in a state that cgroup_walk_tree_end() is not needed - * and will sigsegv and in a state that cgroup_walk_tree_end() is needed - * to free allocated memory. Complete review is needed! - * @par Example of iterator usage: - * @code - * void *handle; // our iterator handle - * my_type item; // the data returned by the iterator - * int ret; - * ret = iterator_name_begin(&handle, &item); - * while (ret == 0) { - * // process the item here - * ret = iterator_name_begin(&handle, &item); - * } - * if (ret != ECGEOF) { - * // process the error here - * } - * iterator_name_end(&handle); - * @endcode - * - * @name Walk through control group filesystem - * @{ - * This iterator returns all subgroups of given control group. It can be used - * to return all groups in given hierarchy, when root control group is provided. - */ - -/** - * Type of the walk. - */ -enum cgroup_walk_type { - /** - * Pre-order directory walk, return a directory first and then its - * subdirectories. - * E.g. directories would be returned in this order: - * @code - * / - * /group - * /group/subgroup1 - * /group/subgroup1/subsubgroup - * /group/subgroup2 - * @endcode - */ - CGROUP_WALK_TYPE_PRE_DIR = 0x1, - /** - * Post-order directory walk, return subdirectories of a directory - * first and then the directory itself. - * E.g. directories would be returned in this order: - * @code - * /group/subgroup1/subsubgroup - * /group/subgroup1 - * /group/subgroup2 - * /group - * / - * @endcode - */ - CGROUP_WALK_TYPE_POST_DIR = 0x2, -}; - -/** - * Type of returned entity. - */ -enum cgroup_file_type { - CGROUP_FILE_TYPE_FILE, /**< File. */ - CGROUP_FILE_TYPE_DIR, /**< Directory. */ - CGROUP_FILE_TYPE_OTHER, /**< Directory. @todo really? */ -}; - -/** - * Information about found directory (= a control group). - */ -struct cgroup_file_info { - /** Type of the entity. */ - enum cgroup_file_type type; - /** Name of the entity. */ - const char *path; - /** Name of its parent. */ - const char *parent; - /** - * Full path to the entity. To get path relative to the root of the - * walk, you must store its @c full_path (or its length) - * and calculate the relative path by yourself. - */ - const char *full_path; - /** - * Depth of the entity, how many directories below the root of - * walk it is. - */ - short depth; -}; - -/** - * Walk through the directory tree for the specified controller. - * The directory representing @c base_path is returned in @c info. - * Use cgroup_walk_tree_set_flags() to specify, in which order should be next - * directories returned. - * @param controller Name of the controller, for which we want to walk - * the directory tree. - * @param base_path Begin walking from this path. Use "/" to walk through - * full hierarchy. - * @param depth The maximum depth to which the function should walk, 0 - * implies all the way down. - * @param handle Handle to be used during iteration. - * @param info Info filled and returned about directory information. - * @param base_level Opaque integer which you must pass to subsequent - * cgroup_walk_tree_next. - * @todo why base_level is not hidden in **handle? - * @return #ECGEOF when there is no node. - */ -int cgroup_walk_tree_begin(const char *controller, const char *base_path, int depth, - void **handle, struct cgroup_file_info *info, - int *base_level); -/** - * Get the next directory in the walk. - * @param depth The maximum depth to which the function should walk, 0 - * implies all the way down. - * @param handle Handle to be used during iteration. - * @param info Info filled and returned about the next directory. - * @param base_level Value of base_level returned by cgroup_walk_tree_begin(). - * @return #ECGEOF when we are done walking through the nodes. - */ -int cgroup_walk_tree_next(int depth, void **handle, - struct cgroup_file_info *info, int base_level); - -/** - * Release the iterator. - */ -int cgroup_walk_tree_end(void **handle); - -/** - * Set the flags for walk_tree. Currently available flags are in - * #cgroup_walk_type enum. - * @param handle Handle of the iterator. - * @param flags - */ -int cgroup_walk_tree_set_flags(void **handle, int flags); - -/** - * Read the value of the given variable for the specified - * controller and control group. - * The value is read up to newline character or at most max-1 characters, - * whichever comes first (i.e. similar to fgets()). - * @param controller Name of the controller for which stats are requested. - * @param path Path to control group, relative to hierarchy root. - * @param name is variable name. - * @param handle Handle to be used during iteration. - * @param buffer Buffer to read the value into. - * The buffer is always zero-terminated. - * @param max Maximal lenght of the buffer - * @return #ECGEOF when the stats file is empty. - */ - -int cgroup_read_value_begin(const char *controller, const char *path, - char *name, void **handle, char *buffer, int max); - -/** - * Read the next string from the given variable handle - * which is generated by cgroup_read_stats_begin() function. - * the value is read up to newline character or at most max-1 characters, - * whichever comes first (i.e. similar to fgets()) per - * cgroup_read_stats_next() call - * @param handle Handle to be used during iteration. - * @param data returned the string. - * @param buffer Buffer to read the value into. - * The buffer is always zero-terminated. - * @param max Maximal lenght of the buffer - * @return #ECGEOF when the iterator finishes getting the list of stats. - */ -int cgroup_read_value_next(void **handle, char *buffer, int max); - -/** - * Release the iterator. - */ -int cgroup_read_value_end(void **handle); - -/** - * @} - * - * @name Read group stats - * libcgroup's cgroup_get_value_string() reads only relatively short parametrs - * of a group. Use following functions to read @c stats parameter, which can - * be quite long. - */ - -/** - * Maximum length of a value in stats file. - */ -#define CG_VALUE_MAX 100 -/** - * One item in stats file. - */ -struct cgroup_stat { - char name[FILENAME_MAX]; - char value[CG_VALUE_MAX]; -}; - -/** - * Read the statistics values (= @c stats parameter) for the specified - * controller and control group. One line is returned per - * cgroup_read_stats_begin() and cgroup_read_stats_next() call. - * @param controller Name of the controller for which stats are requested. - * @param path Path to control group, relative to hierarchy root. - * @param handle Handle to be used during iteration. - * @param stat Returned first item in the stats file. - * @return #ECGEOF when the stats file is empty. - */ -int cgroup_read_stats_begin(const char *controller, const char *path, void **handle, - struct cgroup_stat *stat); - -/** - * Read the next stat value. - * @param handle Handle to be used during iteration. - * @param stat Returned next item in the stats file. - * @return #ECGEOF when the iterator finishes getting the list of stats. - */ -int cgroup_read_stats_next(void **handle, struct cgroup_stat *stat); - -/** - * Release the iterator. - */ -int cgroup_read_stats_end(void **handle); - -/** - * @} - * - * @name List all tasks in a group - * Use following functions to read @c tasks file of a group. - * @{ - */ - -/** - * Read the tasks file to get the list of tasks in a cgroup. - * @param cgroup Name of the cgroup. - * @param controller Name of the cgroup subsystem. - * @param handle Handle to be used in the iteration. - * @param pid The pid read from the tasks file. - * @return #ECGEOF when the group does not contain any tasks. - */ -int cgroup_get_task_begin(const char *cgroup, const char *controller, void **handle, - pid_t *pid); - -/** - * Read the next task value. - * @param handle The handle used for iterating. - * @param pid The variable where the value will be stored. - * - * @return #ECGEOF when the iterator finishes getting the list of tasks. - */ -int cgroup_get_task_next(void **handle, pid_t *pid); - -/** - * Release the iterator. - */ -int cgroup_get_task_end(void **handle); - -/** - * @} - * - * @name List mounted controllers - * Use following function to list mounted controllers and to see, how they - * are mounted together in hierarchies. - * Use cgroup_get_all_controller_begin() (see later) to list all controllers, - * including those which are not mounted. - * @{ - */ - -/** - * Information about mounted controller. - */ -struct cgroup_mount_point { - /** Name of the controller. */ - char name[FILENAME_MAX]; - /** Mount point of the controller. */ - char path[FILENAME_MAX]; -}; - -/** - * Read the mount table to give a list where each controller is - * mounted. - * @param handle Handle to be used for iteration. - * @param info The variable where the path to the controller is stored. - * @return #ECGEOF when no controllers are mounted. - */ -int cgroup_get_controller_begin(void **handle, struct cgroup_mount_point *info); - -/** - * Read the next mounted controller. - * While walking through the mount table, the controllers are - * returned in order of their mount points, i.e. controllers mounted together - * in one hierarchy are returned next to each other. - * @param handle Handle to be used for iteration. - * @param info The variable where the path to the controller is stored. - * @return #ECGEOF when all controllers were already returned. - */ -int cgroup_get_controller_next(void **handle, struct cgroup_mount_point *info); - -/** - * Release the iterator. - */ -int cgroup_get_controller_end(void **handle); - -/** - * @} - * - * @name List all controllers - * Use following functions to list all controllers, including those which are - * not mounted. The controllers are returned in the same order as in - * /proc/cgroups file, i.e. mostly random. - */ - -/** - * Detailed information about available controller. - */ -struct controller_data { - /** Controller name. */ - char name[FILENAME_MAX]; - /** - * Hierarchy ID. Controllers with the same hierarchy ID - * are mounted together as one hierarchy. Controllers with - * ID 0 are not currently mounted anywhere. - */ - int hierarchy; - /** Number of groups. */ - int num_cgroups; - /** Enabled flag. */ - int enabled; -}; - -/** - * Read the first of controllers from /proc/cgroups. - * @param handle Handle to be used for iteration. - * @param info The structure which will be filled with controller data. - */ -int cgroup_get_all_controller_begin(void **handle, - struct controller_data *info); -/** - * Read next controllers from /proc/cgroups. - * @param handle Handle to be used for iteration. - * @param info The structure which will be filled with controller data. - */ -int cgroup_get_all_controller_next(void **handle, struct controller_data *info); - -/** - * Release the iterator - */ -int cgroup_get_all_controller_end(void **handle); - -/** - * @} - * - * @name List all mount points of a controller. - * Use following functions to list all mount points of a hierarchy with given - * controller. - */ - -/** - * Read the first mount point of the hierarchy with given controller. - * The first is the same as the mount point returned by - * cgroup_get_subsys_mount_point(). - * @param handle Handle to be used for iteration. - * @param controller Controller name. - * @param path Buffer to fill the path into. The buffer must be at least - * FILENAME_MAX characters long. - */ -int cgroup_get_subsys_mount_point_begin(const char *controller, void **handle, - char *path); -/** - * Read next mount point of the hierarchy with given controller. - * @param handle Handle to be used for iteration. - * @param path Buffer to fill the path into. The buffer must be at least - * FILENAME_MAX characters long. - */ -int cgroup_get_subsys_mount_point_next(void **handle, - char *path); - -/** - * Release the iterator. - */ -int cgroup_get_subsys_mount_point_end(void **handle); - -/** - * @} - * @} - */ - -__END_DECLS - -#endif /* _LIBCGROUP_ITERATORS_H */ diff --git a/include/libcgroup/log.h b/include/libcgroup/log.h deleted file mode 100644 index 0dd03b41..00000000 --- a/include/libcgroup/log.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef _LIBCGROUP_LOG_H -#define _LIBCGROUP_LOG_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#ifndef SWIG -#include -#endif - -#include - -__BEGIN_DECLS - -/** - * @defgroup group_log 7. Logging - * @{ - * - * @name Logging - * @{ - * Libcgroup allows applications to register a callback function which - * libcgroup will call when it wants to log something. Each log message - * has associated a log level. As described in previous chapter, most libcgroup - * functions return an error code, which described root cause of the failure - * and log messages might provide further details about these failures and other - * notable events. - * - * @par - * The logging callback can be set at any time, but setting the callback before - * any other libcgroup function (including cgroup_init()) is highly recommended. - * If no logger is set before cgroup_init() is called, default logger is - * automatically set, logging CGROUP_LOG_ERROR messages to stdout. - * - * @par Setting log level - * Some of the functions below set the log level as integer. - * Application can set directly a value of enum #cgroup_log_level or use - * value -1 to set the log level automatically. In this case, libcgroup - * inspects environment variable CGROUP_LOGLEVEL if it is set - * and contains any of these values: ERROR, WARNING, - * INFO, DEBUG or integer number representing value from - * enum #cgroup_log_level. If CGROUP_LOGLEVEL is not set or its value - * is not valid, CGROUP_LOG_ERROR is set as default log level. - * - * @par Example: - * Following short example shows custom libcgroup logger sending all log - * messages to stderr: - * @code - * static void my_logger(void *userdata, int level, const char *fmt, va_list ap) - * { - * vfprintf(stderr, fmt, ap); - * } - * - * int main(int argc, char **argv) - * { - * int ret; - * - * cgroup_set_logger(my_logger, -1, NULL); - * ret = cgroup_init(); - * if (ret) { - * ... - * } - * ... - * @endcode - */ - -/** - * Level of importance of a log message. - */ -enum cgroup_log_level { - /** - * Something serious happened and libcgroup failed to perform requested - * operation. - */ - CGROUP_LOG_ERROR = 1, - /** - * Something bad happened but libcgroup recovered from the error. - */ - CGROUP_LOG_WARNING, - /** - * Something interesting happened and the message might be useful to the - * user. - */ - CGROUP_LOG_INFO, - /** - * Debugging messages useful to libcgroup developers. - */ - CGROUP_LOG_DEBUG, -}; - -typedef void (*cgroup_logger_callback)(void *userdata, int level, - const char *fmt, va_list ap); - -/** - * Set libcgroup logging callback. All log messages with equal or lower log - * level will be sent to the application's callback. There can be only - * one callback logger set, the previous callback is replaced with the new one - * by calling this function. - * Use NULL as the logger callback to completely disable libcgroup logging. - * - * @param logger The callback. - * @param loglevel The log level. Use value -1 to automatically discover the - * level from CGROUP_LOGLEVEL environment variable. - * @param userdata Application's data which will be provided back to the - * callback. - */ -extern void cgroup_set_logger(cgroup_logger_callback logger, int loglevel, - void *userdata); - -/** - * Set libcgroup logging to stdout. All messages with the given loglevel - * or below will be sent to standard output. Previous logger set by - * cgroup_set_logger() is replaced. - * - * @param loglevel The log level. Use value -1 to automatically discover the - * level from CGROUP_LOGLEVEL environment variable. - */ -extern void cgroup_set_default_logger(int loglevel); - -/** - * Change current loglevel. - * @param loglevel The log level. Use value -1 to automatically discover the - * level from CGROUP_LOGLEVEL environment variable. - */ -extern void cgroup_set_loglevel(int loglevel); - -/** - * Libcgroup log function. This is for applications which are too lazy to set - * up their own complex logging and miss-use libcgroup for that purpose. - * I.e. this function should be used only by simple command-line tools. - * This logging automatically benefits from CGROUP_LOGLEVEL env. variable. - */ -extern void cgroup_log(int loglevel, const char *fmt, ...); - -/** - * Parse levelstr string for information about desired loglevel. The levelstr - * is usually a value of the CGROUP_LOGLEVEL environment variable. - * @param levelstr String containing desired loglevel. - */ -extern int cgroup_parse_log_level_str(const char *levelstr); -/** - * @} - * @} - */ -__END_DECLS - -#endif /* _LIBCGROUP_LOG_H */ diff --git a/include/libcgroup/tasks.h b/include/libcgroup/tasks.h deleted file mode 100644 index aad438a2..00000000 --- a/include/libcgroup/tasks.h +++ /dev/null @@ -1,209 +0,0 @@ -#ifndef _LIBCGROUP_TASKS_H -#define _LIBCGROUP_TASKS_H - -#ifndef _LIBCGROUP_H_INSIDE -#error "Only should be included directly." -#endif - -#include - -#ifndef SWIG -#include -#include -#endif - -__BEGIN_DECLS - -/** Flags for cgroup_change_cgroup_uid_gid(). */ -enum cgflags { - /** Use cached rules, do not read rules from disk. */ - CGFLAG_USECACHE = 0x01, - /** Use cached templates, do not read templates from disk. */ - CGFLAG_USE_TEMPLATE_CACHE = 0x02, -}; - -/** Flags for cgroup_register_unchanged_process(). */ -enum cgroup_daemon_type { - /** - * The daemon must not touch the given task, i.e. it never moves it - * to any controlgroup. - */ - CGROUP_DAEMON_UNCHANGE_CHILDREN = 0x1, - CGROUP_DAEMON_CANCEL_UNCHANGE_PROCESS = 0x2, -}; - -/** - * @defgroup group_tasks 4. Manipulation with tasks - * @{ - * - * @name Simple task assignment - * @{ - * Applications can use following functions to simply put a task into given - * control group and find a groups where given tasks is. - */ - -/** - * Move current task (=thread) to given control group. - * @param cgroup Destination control group. - */ -int cgroup_attach_task(struct cgroup *cgroup); - -/** - * Move given task (=thread) to to given control group. - * @param cgroup Destination control group. - * @param tid The task to move. - */ -int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid); - -/** - * Changes the cgroup of a task based on the path provided. In this case, - * the user must already know into which cgroup the task should be placed and - * no rules will be parsed. - * - * @param path Name of the destination group. - * @param pid The task to move. - * @param controllers List of controllers. - * - * @todo should this function be really public? - */ -int cgroup_change_cgroup_path(const char *path, pid_t pid, - const char * const controllers[]); - -/** - * Get the current control group path where the given task is. - * @param pid The task to find. - * @param controller The controller (hierarchy), where to find the task. - * @param current_path The path to control group, where the task has been found. - * The patch is relative to the root of the hierarchy. The caller must - * free this memory. - */ -int cgroup_get_current_controller_path(pid_t pid, const char *controller, - char **current_path); - -/** - * @} - * - * @name Rules - * @{ - * @c libcgroup can move tasks to control groups using simple rules, loaded - * from configuration file. See cgrules.conf man page to see format of the file. - * Following functions can be used to load these rules from a file. - */ - -/** - * Initializes the rules cache and load it from /etc/cgrules.conf. - * @todo add parameter with the filename? - */ -int cgroup_init_rules_cache(void); - -/** - * Reloads the rules list from /etc/cgrules.conf. This function - * is probably NOT thread safe (calls cgroup_parse_rules_config()). - */ -int cgroup_reload_cached_rules(void); - -/** - * Print the cached rules table. This function should be called only after - * first calling cgroup_parse_config(), but it will work with an empty rule - * list. - * @param fp Destination file, where the rules will be printed. - */ -void cgroup_print_rules_config(FILE *fp); - -/** - * @} - * @name Rule based task assignment - * @{ - * @c libcgroup can move tasks to control groups using simple rules, loaded - * from configuration file. See cgrules.conf man page to see format of the file. - * Applications can move tasks to control groups based on these rules using - * following functions. - */ - -/** - * Changes the cgroup of all running PIDs based on the rules in the config - * file. If a rules exists for a PID, then the PID is placed in the correct - * group. - * - * This function may be called after creating new control groups to move - * running PIDs into the newly created control groups. - * @return 0 on success, < 0 on error - */ -int cgroup_change_all_cgroups(void); - -/** - * Changes the cgroup of a program based on the rules in the config file. - * If a rule exists for the given UID, GID or PROCESS NAME, then the given - * PID is placed into the correct group. By default, this function parses - * the configuration file each time it is called. - * - * The flags can alter the behavior of this function: - * CGFLAG_USECACHE: Use cached rules instead of parsing the config file - * CGFLAG_USE_TEMPLATE_CACHE: Use cached templates instead of - * parsing the config file - * - * This function may NOT be thread safe. - * @param uid The UID to match. - * @param gid The GID to match. - * @param procname The PROCESS NAME to match. - * @param pid The PID of the process to move. - * @param flags Bit flags to change the behavior, as defined in enum #cgflags. - * @todo Determine thread-safeness and fix of not safe. - */ -int cgroup_change_cgroup_flags(uid_t uid, gid_t gid, - const char *procname, pid_t pid, int flags); - -/** - * Changes the cgroup of a program based on the rules in the config file. If a - * rule exists for the given UID or GID, then the given PID is placed into the - * correct group. By default, this function parses the configuration file each - * time it is called. - * - * This function may NOT be thread safe. - * @param uid The UID to match. - * @param gid The GID to match. - * @param pid The PID of the process to move. - * @param flags Bit flags to change the behavior, as defined in enum #cgflags. - * @todo Determine thread-safeness and fix if not safe. - */ -int cgroup_change_cgroup_uid_gid_flags(uid_t uid, gid_t gid, - pid_t pid, int flags); - -/** - * Provides backwards-compatibility with older versions of the API. This - * function is deprecated, and cgroup_change_cgroup_uid_gid_flags() should be - * used instead. In fact, this function simply calls the newer one with flags - * set to 0 (none). - * @param uid The UID to match. - * @param gid The GID to match. - * @param pid The PID of the process to move. - */ -int cgroup_change_cgroup_uid_gid(uid_t uid, gid_t gid, pid_t pid); - -/** - * @} - * @name Communication with cgrulesengd daemon - * @{ - * Users can use cgrulesengd daemon to move tasks to groups based on the rules - * automatically when they change their UID, GID or executable name. - * The daemon allows tasks to be 'sticky', i.e. all rules are ignored for these - * tasks and the daemon never moves them. - */ - -/** - * Register the unchanged process to a cgrulesengd daemon. This process - * is never moved to another control group by the daemon. - * If the daemon does not work, this function returns 0 as success. - * @param pid The task id. - * @param flags Bit flags to change the behavior, as defined in - * #cgroup_daemon_type - */ -int cgroup_register_unchanged_process(pid_t pid, int flags); - -/** - * @} - * @} - */ -__END_DECLS - -#endif /* _LIBCGROUP_TASKS_H */ diff --git a/libcgroup.doxyfile b/libcgroup.doxyfile deleted file mode 100644 index 0716436b..00000000 --- a/libcgroup.doxyfile +++ /dev/null @@ -1,1519 +0,0 @@ -# Doxyfile 1.6.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = libcgroup - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = doc/generated - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = YES - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = YES - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = YES - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = include - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = NO - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# If the HTML_TIMESTAMP tag is set to YES then the generated HTML -# documentation will contain the timesstamp. - -HTML_TIMESTAMP = NO - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's -# filter section matches. -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = YES - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) -# there is already a search function so this one should typically -# be disabled. - -SEARCHENGINE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = YES - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = YES - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = NO - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = NO - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = YES - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = NO - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = NO - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = NO - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = YES - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/libcgroup.pc.in b/libcgroup.pc.in deleted file mode 100644 index bd925e52..00000000 --- a/libcgroup.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libcgroup -Description: Control Group Configuration Library -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lcgroup -Cflags: -I${includedir} diff --git a/m4/ax_code_coverage.m4 b/m4/ax_code_coverage.m4 deleted file mode 100644 index a257469f..00000000 --- a/m4/ax_code_coverage.m4 +++ /dev/null @@ -1,264 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_code_coverage.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CODE_COVERAGE() -# -# DESCRIPTION -# -# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS, -# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included -# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every -# build target (program or library) which should be built with code -# coverage support. Also defines CODE_COVERAGE_RULES which should be -# substituted in your Makefile; and $enable_code_coverage which can be -# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined -# and substituted, and corresponds to the value of the -# --enable-code-coverage option, which defaults to being disabled. -# -# Test also for gcov program and create GCOV variable that could be -# substituted. -# -# Note that all optimisation flags in CFLAGS must be disabled when code -# coverage is enabled. -# -# Usage example: -# -# configure.ac: -# -# AX_CODE_COVERAGE -# -# Makefile.am: -# -# @CODE_COVERAGE_RULES@ -# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ... -# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ... -# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ... -# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ... -# -# This results in a "check-code-coverage" rule being added to any -# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module -# has been configured with --enable-code-coverage). Running `make -# check-code-coverage` in that directory will run the module's test suite -# (`make check`) and build a code coverage report detailing the code which -# was touched, then print the URI for the report. -# -# In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined -# instead of CODE_COVERAGE_LIBS. They are both still defined, but use of -# CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is -# deprecated. They have the same value. -# -# This code was derived from Makefile.decl in GLib, originally licenced -# under LGPLv2.1+. -# -# LICENSE -# -# Copyright (c) 2012, 2016 Philip Withnall -# Copyright (c) 2012 Xan Lopez -# Copyright (c) 2012 Christian Persch -# Copyright (c) 2012 Paolo Borelli -# Copyright (c) 2012 Dan Winship -# Copyright (c) 2015 Bastien ROUCARIES -# -# This library is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or (at -# your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . - -#serial 20 - -AC_DEFUN([AX_CODE_COVERAGE],[ - dnl Check for --enable-code-coverage - AC_REQUIRE([AC_PROG_SED]) - - # allow to override gcov location - AC_ARG_WITH([gcov], - [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])], - [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov], - [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov]) - - AC_MSG_CHECKING([whether to build with code coverage support]) - AC_ARG_ENABLE([code-coverage], - AS_HELP_STRING([--enable-code-coverage], - [Whether to enable code coverage support]),, - enable_code_coverage=no) - - AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes]) - AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) - AC_MSG_RESULT($enable_code_coverage) - - AS_IF([ test "$enable_code_coverage" = "yes" ], [ - # check for gcov - AC_CHECK_TOOL([GCOV], - [$_AX_CODE_COVERAGE_GCOV_PROG_WITH], - [:]) - AS_IF([test "X$GCOV" = "X:"], - [AC_MSG_ERROR([gcov is needed to do coverage])]) - AC_SUBST([GCOV]) - - dnl Check if gcc is being used - AS_IF([ test "$GCC" = "no" ], [ - AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage]) - ]) - - AC_CHECK_PROG([LCOV], [lcov], [lcov]) - AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) - - AS_IF([ test -z "$LCOV" ], [ - AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed]) - ]) - - AS_IF([ test -z "$GENHTML" ], [ - AC_MSG_ERROR([Could not find genhtml from the lcov package]) - ]) - - dnl Build the code coverage flags - dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility - CODE_COVERAGE_CPPFLAGS="-DNDEBUG" - CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" - CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" - CODE_COVERAGE_LIBS="-lgcov" - CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS" - - AC_SUBST([CODE_COVERAGE_CPPFLAGS]) - AC_SUBST([CODE_COVERAGE_CFLAGS]) - AC_SUBST([CODE_COVERAGE_CXXFLAGS]) - AC_SUBST([CODE_COVERAGE_LIBS]) - AC_SUBST([CODE_COVERAGE_LDFLAGS]) - - [CODE_COVERAGE_RULES_CHECK=' - -$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check - $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture -'] - [CODE_COVERAGE_RULES_CAPTURE=' - $(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS) - $(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS) - -@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp - $(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS) - @echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html" -'] - [CODE_COVERAGE_RULES_CLEAN=' -clean: code-coverage-clean -distclean: code-coverage-clean -code-coverage-clean: - -$(LCOV) --directory $(top_builddir) -z - -rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY) - -find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete -'] - ], [ - [CODE_COVERAGE_RULES_CHECK=' - @echo "Need to reconfigure with --enable-code-coverage" -'] - CODE_COVERAGE_RULES_CAPTURE="$CODE_COVERAGE_RULES_CHECK" - CODE_COVERAGE_RULES_CLEAN='' - ]) - -[CODE_COVERAGE_RULES=' -# Code coverage -# -# Optional: -# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting. -# Multiple directories may be specified, separated by whitespace. -# (Default: $(top_builddir)) -# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated -# by lcov for code coverage. (Default: -# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info) -# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage -# reports to be created. (Default: -# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage) -# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage, -# set to 0 to disable it and leave empty to stay with the default. -# (Default: empty) -# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov -# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) -# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov -# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) -# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov -# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the -# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) -# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov -# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) -# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering -# lcov instance. (Default: empty) -# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov -# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) -# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the -# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) -# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml -# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) -# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore -# -# The generated report will be titled using the $(PACKAGE_NAME) and -# $(PACKAGE_VERSION). In order to add the current git hash to the title, -# use the git-version-gen script, available online. - -# Optional variables -CODE_COVERAGE_DIRECTORY ?= $(top_builddir) -CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info -CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage -CODE_COVERAGE_BRANCH_COVERAGE ?= -CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ ---rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) -CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) -CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)" -CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) -CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) -CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?= -CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) -CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\ -$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ ---rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) -CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULTS) -CODE_COVERAGE_IGNORE_PATTERN ?= - -code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V)) -code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY)) -code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\ - $(CODE_COVERAGE_OUTPUT_FILE); -code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V)) -code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY)) -code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\ - $(CODE_COVERAGE_IGNORE_PATTERN); -code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V)) -code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY)) -code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY); -code_coverage_quiet = $(code_coverage_quiet_$(V)) -code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) -code_coverage_quiet_0 = --quiet - -# sanitizes the test-name: replaces with underscores: dashes and dots -code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1))) - -# Use recursive makes in order to ignore errors during check -check-code-coverage:'"$CODE_COVERAGE_RULES_CHECK"' - -# Capture code coverage data -code-coverage-capture: code-coverage-capture-hook'"$CODE_COVERAGE_RULES_CAPTURE"' - -# Hook rule executed before code-coverage-capture, overridable by the user -code-coverage-capture-hook: - -'"$CODE_COVERAGE_RULES_CLEAN"' - -GITIGNOREFILES ?= -GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY) - -A''M_DISTCHECK_CONFIGURE_FLAGS ?= -A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage - -.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean -'] - - AC_SUBST([CODE_COVERAGE_RULES]) - m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])]) -]) diff --git a/samples/Makefile.am b/samples/Makefile.am deleted file mode 100644 index 26bae335..00000000 --- a/samples/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -EXTRA_DIST = cgconfig.conf cgred.conf cgrules.conf cgconfig.sysconfig \ - cgsnapshot_blacklist.conf diff --git a/samples/cgconfig.conf b/samples/cgconfig.conf deleted file mode 100644 index de77e4b8..00000000 --- a/samples/cgconfig.conf +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright IBM Corporation. 2007 -# -# Authors: Balbir Singh -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -#group daemons/www { -# perm { -# task { -# uid = root; -# gid = webmaster; -# } -# admin { -# uid = root; -# gid = root; -# } -# } -# cpu { -# cpu.shares = 1000; -# } -#} -# -#group daemons/ftp { -# perm { -# task { -# uid = root; -# gid = ftpmaster; -# } -# admin { -# uid = root; -# gid = root; -# } -# } -# cpu { -# cpu.shares = 500; -# } -#} -# -#mount { -# cpu = /mnt/cgroups/cpu; -# cpuacct = /mnt/cgroups/cpuacct; -#} diff --git a/samples/cgconfig.sysconfig b/samples/cgconfig.sysconfig deleted file mode 100644 index 5a61bf6e..00000000 --- a/samples/cgconfig.sysconfig +++ /dev/null @@ -1,12 +0,0 @@ -# Service cgconfig can create a default group in all mounted hierarchies and -# move all processes there on boot. If no default rule is specified in -# /etc/cgrules.conf, the default group is named '/sysdefault'. -# This automatically created group(s) can be useful e.g. when using 'cpu' -# controller to limit cpu.shares of this default group and allowing some more -# important group take most of the CPU. -# -# By default, create these groups: -CREATE_DEFAULT=yes - -# Uncomment following line to disable creation of the default group on startup: -# CREATE_DEFAULT=no diff --git a/samples/cgred.conf b/samples/cgred.conf deleted file mode 100644 index 48028793..00000000 --- a/samples/cgred.conf +++ /dev/null @@ -1,27 +0,0 @@ -# /etc/sysconfig/cgred.conf - CGroup Rules Engine Daemon configuration file -# -# The four options listed below (CONFIG_FILE, LOG_FILE, NODAEMON, LOG) are -# the only valid ones. Defining anything else in this file will cause the -# CGroup Rules Engine program to fail. So, don't do it. - -# The pathname to the configuration file for CGroup Rules Engine -CONFIG_FILE="/etc/cgrules.conf" - -# Uncomment the following line to log to specified file instead of syslog -#LOG_FILE="/var/log/cgrulesengd.log" - -# Uncomment the second line to run CGroup Rules Engine in non-daemon mode -NODAEMON="" -#NODAEMON="--nodaemon" - -# Set owner of cgred socket. 'cgexec' tool should have write access there -# (either using suid and/or sgid permissions or Linux capabilities). -SOCKET_USER="" -SOCKET_GROUP="cgred" - -# Uncomment the second line to disable logging for CGroup Rules Engine -# Uncomment the third line to enable more verbose logging. -LOG="" -#LOG="--nolog" -#LOG="-v" - diff --git a/samples/cgrules.conf b/samples/cgrules.conf deleted file mode 100644 index 86300b3d..00000000 --- a/samples/cgrules.conf +++ /dev/null @@ -1,10 +0,0 @@ -# /etc/cgrules.conf -#The format of this file is described in cgrules.conf(5) -#manual page. -# -# Example: -# -#@student cpu,memory usergroup/student/ -#peter cpu test1/ -#% memory test2/ -# End of file diff --git a/samples/cgsnapshot_blacklist.conf b/samples/cgsnapshot_blacklist.conf deleted file mode 100644 index 3d63373e..00000000 --- a/samples/cgsnapshot_blacklist.conf +++ /dev/null @@ -1,20 +0,0 @@ -#cgsnapshot tool configuration file - -#memory -memory.oom_control - -#cpu - -#cpuacct - -#devices - -#cpuset - -#ns - -#freezer - -#net_cls - -#blkio \ No newline at end of file diff --git a/samples/cgsnapshot_whitelist.conf b/samples/cgsnapshot_whitelist.conf deleted file mode 100644 index 2c9ab238..00000000 --- a/samples/cgsnapshot_whitelist.conf +++ /dev/null @@ -1,48 +0,0 @@ -#cgsnapshot tool configuration file - -#memory -memory.memsw.failcnt -memory.memsw.limit_in_bytes -memory.memsw.max_usage_in_bytes -memory.swappiness -memory.use_hierarchy -memory.failcnt -memory.soft_limit_in_bytes -memory.limit_in_bytes -memory.max_usage_in_bytes -memory.move_charge_at_immigrate - -#cpu -cpu.rt_runtime_us -cpu.rt_period_us - -#cpuacct -cpuacct.usage - -#devices -devices.deny -devices.allow -devices.list - -#cpuset -cpuset.memory_spread_slab -cpuset.memory_spread_page -cpuset.memory_migrate -cpuset.sched_relax_domain_level -cpuset.sched_load_balance -cpuset.mem_hardwall -cpuset.mem_exclusive -cpuset.cpu_exclusive -cpuset.mems -cpuset.cpus - -#ns - -#freezer -freezer.state - -#net_cls -net_cls.classid - -#blkio -blkio.weight \ No newline at end of file diff --git a/samples/invalid_namespace_config.conf b/samples/invalid_namespace_config.conf deleted file mode 100644 index 2113aaf8..00000000 --- a/samples/invalid_namespace_config.conf +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright IBM Corporation. 2009 -# -# Authors: Dhaval Giani -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -group www { - perm { - task { - uid = root; - gid = webmaster; - } - admin { - uid = root; - gid = root; - } - } - cpu { - cpu.shares = 1000; - } - cpuacct { - } -} - -group ftp { - perm { - task { - uid = root; - gid = ftpmaster; - } - admin { - uid = root; - gid = root; - } - } - cpu { - cpu.shares = 500; - } - cpuacct { - } -} - -mount { - cpu = /mnt/cgroups; - cpuacct = /mnt/cgroups; -} - -namespace { - cpu = daemons; - #This is invalid since both cpu and cpuacct are mounted at the - #same place but have different namespace - cpuacct = network; -} diff --git a/samples/invalid_namespace_mount_config.conf b/samples/invalid_namespace_mount_config.conf deleted file mode 100644 index e910672c..00000000 --- a/samples/invalid_namespace_mount_config.conf +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright IBM Corporation. 2009 -# -# Authors: Dhaval Giani -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -group www { - perm { - task { - uid = root; - gid = root; - } - admin { - uid = root; - gid = root; - } - } - cpu { - cpu.shares = 1000; - } - cpuacct { - } -} - -group ftp { - perm { - task { - uid = root; - gid = root; - } - admin { - uid = root; - gid = root; - } - } - cpu { - cpu.shares = 500; - } - cpuacct { - } -} - -#This is invalid because we cannot have mount and namespace in the same -#configuration file. -mount { - cpu = /cgroups/cpu; - cpuacct = /cgroups/cpuacct; -} - -namespace { - cpu = daemons; - cpuacct = daemons; -} diff --git a/samples/large_cgconfig.conf.bz2 b/samples/large_cgconfig.conf.bz2 deleted file mode 100644 index ea2e6be7..00000000 Binary files a/samples/large_cgconfig.conf.bz2 and /dev/null differ diff --git a/samples/namespace_config.conf b/samples/namespace_config.conf deleted file mode 100644 index fb60bc64..00000000 --- a/samples/namespace_config.conf +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright IBM Corporation. 2009 -# -# Authors: Dhaval Giani -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -group www { - perm { - task { - uid = root; - gid = root; - } - admin { - uid = root; - gid = root; - } - } - cpu { - cpu.shares = 1000; - } - cpuacct { - } -} - -group ftp { - perm { - task { - uid = root; - gid = root; - } - admin { - uid = root; - gid = root; - } - } - cpu { - cpu.shares = 500; - } - cpuacct { - } -} - -namespace { - cpu = daemons; - cpuacct = daemons; -} diff --git a/scripts/Makefile.am b/scripts/Makefile.am deleted file mode 100644 index 9d0f1916..00000000 --- a/scripts/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -EXTRA_DIST = init.d/cgconfig.in init.d/cgred.in - -if WITH_INITSCRIPT_INSTALL -INITSCRIPTDIR=$(DESTDIR)$(sysconfdir)/rc.d/init.d -install-exec-hook: - $(INSTALL) -d $(INITSCRIPTDIR) - $(INSTALL_SCRIPT) init.d/cgconfig init.d/cgred $(INITSCRIPTDIR) - -uninstall-hook: - rm -f $(INITSCRIPTDIR)/cgconfig $(INITSCRIPTDIR)/cgred -endif diff --git a/scripts/init.d/.gitignore b/scripts/init.d/.gitignore deleted file mode 100644 index a071eebe..00000000 --- a/scripts/init.d/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -cgconfig -cgred diff --git a/scripts/init.d/cgconfig.in b/scripts/init.d/cgconfig.in deleted file mode 100644 index f299d0ff..00000000 --- a/scripts/init.d/cgconfig.in +++ /dev/null @@ -1,206 +0,0 @@ -#!/bin/bash -# -# Start/Stop the workload manager -# -# Copyright IBM Corporation. 2008 -# -# Authors: Balbir Singh -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# cgconfig Control Groups Configuration Startup -# chkconfig: - 5 95 -# description: This script runs the cgconfigparser utility to parse and setup -# the control group filesystem. It uses /etc/cgconfig.conf -# and parses the configuration specified in there. - -### BEGIN INIT INFO -# Provides: cgconfig -# Required-Start: -# Required-Stop: -# Should-Start: ypbind -# Should-Stop: ypbind -# Short-Description: Create and setup control group filesystem(s) -# Description: Create and setup control group filesystem(s) -### END INIT INFO - -# get correct location of binaries from configure -prefix=@prefix@;exec_prefix=@exec_prefix@;sbindir=@sbindir@ -CGCONFIGPARSER_BIN=$sbindir/cgconfigparser -CONFIG_FILE=/etc/cgconfig.conf -servicename=cgconfig -lockfile=/var/lock/subsys/$servicename - -# -# Source LSB routines -# -. /lib/lsb/init-functions - -# read the config -CREATE_DEFAULT=yes -if [ -e /etc/sysconfig/cgconfig ]; then - . /etc/sysconfig/cgconfig -fi - -create_default_groups() { - defaultcgroup= - - if [ -f /etc/cgrules.conf ]; then - read user ctrl defaultcgroup <<< \ - $(grep -m1 '^\*[[:space:]]\+' /etc/cgrules.conf) - if [ -n "$defaultcgroup" -a "$defaultcgroup" = "*" ]; then - log_warning_msg "/etc/cgrules.conf incorrect" - log_warning_msg "Overriding it" - defaultcgroup= - fi - fi - - if [ -z $defaultcgroup ] - then - defaultcgroup=sysdefault/ - fi - - # - # Find all mounted subsystems and create comma-separated list - # of controllers. - # - controllers=`lssubsys 2>/dev/null | tr '\n' ',' | sed s/.$//` - - # - # Create the default group, ignore errors when the default group - # already exists. - # - cgcreate -f 664 -d 775 -g $controllers:$defaultcgroup 2>/dev/null - - # - # special rule for cpusets - # - if echo $controllers | grep -q -w cpuset; then - cpus=`cgget -nv -r cpuset.cpus /` - cgset -r cpuset.cpus=$cpus $defaultcgroup - mems=`cgget -nv -r cpuset.mems /` - cgset -r cpuset.mems=$mems $defaultcgroup - fi - - # - # Classify everything to default cgroup. Ignore errors, some processes - # may exit after ps is run and before cgclassify moves them. - # - cgclassify -g $controllers:$defaultcgroup `ps --no-headers -eL o tid` \ - 2>/dev/null || : -} - -start() { - echo -n "Starting cgconfig service: " - if [ -f "$lockfile" ]; then - log_warning_msg "lock file already exists" - return 0 - fi - - if [ $? -eq 0 ]; then - if [ ! -s $CONFIG_FILE ]; then - log_failure_msg $CONFIG_FILE "is not configured" - return 6 - fi - - $CGCONFIGPARSER_BIN -l $CONFIG_FILE - retval=$? - if [ $retval -ne 0 ]; then - log_failure_msg "Failed to parse " $CONFIG_FILE - return 1 - fi - fi - - if [ $CREATE_DEFAULT = "yes" ]; then - create_default_groups - fi - - touch "$lockfile" - retval=$? - if [ $retval -ne 0 ]; then - log_failure_msg "Failed to touch $lockfile" - return 1 - fi - log_success_msg - return 0 -} - -stop() { - echo -n "Stopping cgconfig service: " - cgclear - rm -f "$lockfile" - log_success_msg - return 0 -} - -trapped() { - # - # Do nothing - # - true -} - -usage() { - echo "$0 " - exit 2 -} - -common() { - # - # main script work done here - # - trap "trapped ABRT" ABRT - trap "trapped QUIT" QUIT - trap "trapped TERM" TERM - trap "trapped INT" INT -} - -restart() { - common - stop - start -} - -RETVAL=0 - -case $1 in - 'stop') - common - stop - RETVAL=$? - ;; - 'start') - common - start - RETVAL=$? - ;; - 'restart'|'reload') - restart - RETVAL=$? - ;; - 'condrestart') - if [ -f "$lockfile" ]; then - restart - RETVAL=$? - fi - ;; - 'status') - if [ -f "$lockfile" ]; then - echo "Running" - exit 0 - else - echo "Stopped" - exit 3 - fi - ;; - *) - usage - ;; -esac - -exit $RETVAL diff --git a/scripts/init.d/cgred.in b/scripts/init.d/cgred.in deleted file mode 100644 index 247ec610..00000000 --- a/scripts/init.d/cgred.in +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash -# -# Start/Stop the CGroups Rules Engine Daemon -# -# Copyright Red Hat Inc. 2008 -# -# Authors: Steve Olivieri -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2.1 of the GNU Lesser General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# cgred CGroups Rules Engine Daemon -# chkconfig: - 14 86 -# description: This is a daemon for automatically classifying processes \ -# into cgroups based on UID/GID. -# -# processname: cgrulesengd -# pidfile: /var/run/cgred.pid -# -### BEGIN INIT INFO -# Provides: cgrulesengd -# Required-Start: $local_fs $syslog $cgconfig -# Required-Stop: $local_fs $syslog -# Should-Start: -# Should-Stop: -# Short-Description: start and stop the cgroups rules engine daemon -# Description: CGroup Rules Engine is a tool for automatically using \ -# cgroups to classify processes -### END INIT INFO - -prefix=@prefix@;exec_prefix=@exec_prefix@;sbindir=@sbindir@ -CGRED_BIN=$sbindir/cgrulesengd -CGRED_CONF=/etc/cgrules.conf - -# Sanity checks -[ -x $CGRED_BIN ] || exit 1 - -# Source function library & LSB routines -. /etc/rc.d/init.d/functions -. /lib/lsb/init-functions - -# Read in configuration options. -if [ -f "/etc/sysconfig/cgred.conf" ] ; then - . /etc/sysconfig/cgred.conf - OPTIONS="$NODAEMON $LOG" - if [ -n "$LOG_FILE" ]; then - OPTIONS="$OPTIONS --logfile=$LOG_FILE" - fi - if [ -n "$SOCKET_USER" ]; then - OPTIONS="$OPTIONS -u $SOCKET_USER" - fi - if [ -n "$SOCKET_GROUP" ]; then - OPTIONS="$OPTIONS -g $SOCKET_GROUP" - fi -else - OPTIONS="" -fi - -# For convenience -processname=cgrulesengd -servicename=cgred -lockfile="/var/lock/subsys/$servicename" -pidfile=/var/run/cgred.pid - -start() -{ - echo -n $"Starting CGroup Rules Engine Daemon: " - if [ -f "$lockfile" ]; then - log_failure_msg "$servicename is already running with PID `cat ${pidfile}`" - return 0 - fi - num=`grep "cgroup" /proc/mounts | awk '$3=="cgroup"' | wc -l` - if [ $num -eq 0 ]; then - echo - log_failure_msg $"Cannot find cgroups, is cgconfig service running?" - return 1 - fi - daemon --check $servicename --pidfile $pidfile $CGRED_BIN $OPTIONS - retval=$? - echo - if [ $retval -ne 0 ]; then - return 7 - fi - touch "$lockfile" - if [ $? -ne 0 ]; then - return 1 - fi - echo "`pidof $processname`" > $pidfile - return 0 -} - -stop() -{ - echo -n $"Stopping CGroup Rules Engine Daemon..." - if [ ! -f $pidfile ]; then - log_success_msg - return 0 - fi - killproc -p $pidfile -TERM "$processname" - retval=$? - echo - if [ $retval -ne 0 ]; then - return 1 - fi - rm -f "$lockfile" "$pidfile" - return 0 -} - -RETVAL=0 - -# See how we are called -case "$1" in - start) - start - RETVAL=$? - ;; - stop) - stop - RETVAL=$? - ;; - status) - status -p $pidfile $servicename - RETVAL=$? - ;; - restart) - stop - start - RETVAL=$? - ;; - condrestart) - if [ -f "$lockfile" ]; then - stop - start - RETVAL=$? - fi - ;; - reload|flash) - if [ -f "$lockfile" ]; then - echo $"Reloading rules configuration..." - kill -s 12 `cat ${pidfile}` - RETVAL=$? - if [ $RETVAL -eq 0 ] ; then - log_success_msg - else - log_failure_msg - fi - else - log_failure_msg "$servicename is not running." - fi - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}" - RETVAL=2 - ;; -esac - -exit $RETVAL diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index 14925462..00000000 --- a/src/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -lex.c -parse.c -parse.h diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 9fc965ba..00000000 --- a/src/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -@CODE_COVERAGE_RULES@ - -if WITH_BINDINGS -BINDINGS_SUBDIR = bindings -endif - -SUBDIRS = . daemon pam tools $(BINDINGS_SUBDIR) - -# generate parse.h from parse.y -AM_YFLAGS = -d - -CLEANFILES = lex.c parse.c parse.h - -INCLUDES = -I$(top_srcdir)/include -lib_LTLIBRARIES = libcgroup.la libcgroupfortesting.la -libcgroup_la_SOURCES = parse.h parse.y lex.l api.c config.c libcgroup-internal.h libcgroup.map wrapper.c log.c -libcgroup_la_LIBADD = -lpthread $(CODE_COVERAGE_LIBS) -libcgroup_la_CFLAGS = $(CODE_COVERAGE_CFLAGS) -DSTATIC=static -libcgroup_la_LDFLAGS = -Wl,--version-script,$(srcdir)/libcgroup.map \ - -version-number $(LIBRARY_VERSION_MAJOR):$(LIBRARY_VERSION_MINOR):$(LIBRARY_VERSION_RELEASE) - -libcgroupfortesting_la_SOURCES = $(libcgroup_la_SOURCES) -libcgroupfortesting_la_LIBADD = -lpthread $(CODE_COVERAGE_LIBS) -libcgroupfortesting_la_CFLAGS = $(CODE_COVERAGE_CFLAGS) -DSTATIC= -DUNIT_TEST -libcgroupfortesting_la_LDFLAGS = -Wl,--version-script,$(top_srcdir)/tests/gunit/libcgroup_unittest.map \ - -version-number $(LIBRARY_VERSION_MAJOR):$(LIBRARY_VERSION_MINOR):$(LIBRARY_VERSION_RELEASE) diff --git a/src/api.c b/src/api.c deleted file mode 100644 index 24ae48d3..00000000 --- a/src/api.c +++ /dev/null @@ -1,5152 +0,0 @@ -/* - * Copyright IBM Corporation. 2007 - * - * Author: Dhaval Giani - * Author: Balbir Singh - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * TODOs: - * 1. Add more APIs for the control groups. - * 2. Handle the configuration related APIs. - * - * Code initiated and designed by Dhaval Giani. All faults are most likely - * his mistake. - * - * Bharata B Rao is willing is take blame - * for mistakes in APIs for reading statistics. - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The errno which happend the last time (have to be thread specific) - */ -__thread int last_errno; - -#define MAXLEN 256 - -/* the value have to be thread specific */ -static __thread char errtext[MAXLEN]; - -/* Task command name length */ -#define TASK_COMM_LEN 16 - -/* Check if cgroup_init has been called or not. */ -static int cgroup_initialized; - -/* List of configuration rules */ -static struct cgroup_rule_list rl; - -/* Temporary list of configuration rules (for non-cache apps) */ -static struct cgroup_rule_list trl; - -/* Lock for the list of rules (rl) */ -static pthread_rwlock_t rl_lock = PTHREAD_RWLOCK_INITIALIZER; - -/* Namespace */ -__thread char *cg_namespace_table[CG_CONTROLLER_MAX]; - -pthread_rwlock_t cg_mount_table_lock = PTHREAD_RWLOCK_INITIALIZER; -struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX]; - -const char * const cgroup_strerror_codes[] = { - "Cgroup is not compiled in", - "Cgroup is not mounted", - "Cgroup does not exist", - "Cgroup has not been created", - "Cgroup one of the needed subsystems is not mounted", - "Cgroup, request came in from non owner", - "Cgroup controllers are bound to different mount points", - "Cgroup, operation not allowed", - "Cgroup value set exceeds maximum", - "Cgroup controller already exists", - "Cgroup value already exists", - "Cgroup invalid operation", - "Cgroup, creation of controller failed", - "Cgroup operation failed", - "Cgroup not initialized", - "Cgroup, requested group parameter does not exist", - "Cgroup generic error", - "Cgroup values are not equal", - "Cgroup controllers are different", - "Cgroup parsing failed", - "Cgroup, rules file does not exist", - "Cgroup mounting failed", - "End of File or iterator", - "Failed to parse config file", - "Have multiple paths for the same namespace", - "Controller in namespace does not exist", - "Either mount or namespace keyword has to be specified in the configuration file", - "This kernel does not support this feature", - "Value setting does not succeed", - "Failed to remove a non-empty group", -}; - -static const char * const cgroup_ignored_tasks_files[] = { "tasks", NULL }; - -#ifndef UNIT_TEST -static int cg_get_cgroups_from_proc_cgroups(pid_t pid, char *cgroup_list[], - char *controller_list[], - int list_len); -#endif - -static int cg_chown(const char *filename, uid_t owner, gid_t group) -{ - if (owner == NO_UID_GID) - owner = getuid(); - if (group == NO_UID_GID) - group = getgid(); - return chown(filename, owner, group); -} -static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) -{ - int ret = 0; - const char *filename = fts->fts_path; - cgroup_dbg("chown: seeing file %s\n", filename); - switch (ent->fts_info) { - case FTS_ERR: - errno = ent->fts_errno; - break; - case FTS_D: - case FTS_DC: - case FTS_NSOK: - case FTS_NS: - case FTS_DNR: - case FTS_DP: - case FTS_F: - case FTS_DEFAULT: - ret = cg_chown(filename, owner, group); - break; - } - if (ret < 0) { - cgroup_warn("Warning: cannot change owner of file %s: %s\n", - filename, strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - } - return ret; -} - -/* - * TODO: Need to decide a better place to put this function. - */ -static int cg_chown_recursive(char **path, uid_t owner, gid_t group) -{ - int ret = 0; - FTS *fts; - - cgroup_dbg("chown: path is %s\n", *path); - fts = fts_open(path, FTS_PHYSICAL | FTS_NOCHDIR | - FTS_NOSTAT, NULL); - if (fts == NULL) { - cgroup_warn("Warning: cannot open directory %s: %s\n", - path, strerror(errno)); - last_errno = errno; - return ECGOTHER; - } - while (1) { - FTSENT *ent; - ent = fts_read(fts); - if (!ent) { - cgroup_warn("Warning: fts_read failed\n"); - break; - } - ret = cg_chown_file(fts, ent, owner, group); - } - fts_close(fts); - return ret; -} - -int cg_chmod_path(const char *path, mode_t mode, int owner_is_umask) -{ - struct stat buf; - mode_t mask = -1U; - - if (owner_is_umask) { - mode_t umask, gmask, omask; - - /* - * Use owner permissions as an umask for group and others - * permissions because we trust kernel to initialize owner - * permissions to something useful. - * Keep SUID and SGID bits. - */ - if (stat(path, &buf) == -1) - goto fail; - umask = S_IRWXU & buf.st_mode; - gmask = umask >> 3; - omask = gmask >> 3; - - mask = umask|gmask|omask|S_ISUID|S_ISGID|S_ISVTX; - } - - if (chmod(path, mode & mask)) - goto fail; - - return 0; - -fail: - cgroup_warn("Warning: cannot change permissions of file %s: %s\n", path, - strerror(errno)); - last_errno = errno; - return ECGOTHER; -} - -int cg_chmod_file(FTS *fts, FTSENT *ent, mode_t dir_mode, - int dirm_change, mode_t file_mode, int filem_change, - int owner_is_umask) -{ - int ret = 0; - const char *filename = fts->fts_path; - - cgroup_dbg("chmod: seeing file %s\n", filename); - - switch (ent->fts_info) { - case FTS_ERR: - errno = ent->fts_errno; - break; - case FTS_D: - case FTS_DC: - case FTS_DNR: - case FTS_DP: - if (dirm_change) - ret = cg_chmod_path(filename, dir_mode, owner_is_umask); - break; - case FTS_F: - case FTS_NSOK: - case FTS_NS: - case FTS_DEFAULT: - if (filem_change) - ret = cg_chmod_path(filename, file_mode, - owner_is_umask); - break; - } - return ret; -} - - -/** - * Changes permissions of all directories and control files (i.e. all - * files except files named in ignore_list. The list must be terminated with - * NULL. - */ -static int cg_chmod_recursive_controller(char *path, mode_t dir_mode, - int dirm_change, mode_t file_mode, int filem_change, - int owner_is_umask, const char * const *ignore_list) -{ - int ret = 0; - int final_ret =0; - FTS *fts; - char *fts_path[2]; - int i, ignored; - - fts_path[0] = path; - fts_path[1] = NULL; - cgroup_dbg("chmod: path is %s\n", path); - - fts = fts_open(fts_path, FTS_PHYSICAL | FTS_NOCHDIR | - FTS_NOSTAT, NULL); - if (fts == NULL) { - cgroup_warn("Warning: cannot open directory %s: %s\n", - fts_path, strerror(errno)); - last_errno = errno; - return ECGOTHER; - } - while (1) { - FTSENT *ent; - ent = fts_read(fts); - if (!ent) { - if (errno != 0) { - cgroup_dbg("fts_read failed\n"); - last_errno = errno; - final_ret = ECGOTHER; - } - break; - } - ignored = 0; - if (ignore_list != NULL) - for (i = 0; ignore_list[i] != NULL; i++) - if (!strcmp(ignore_list[i], ent->fts_name)) { - ignored = 1; - break; - } - if (ignored) - continue; - - ret = cg_chmod_file(fts, ent, dir_mode, dirm_change, - file_mode, filem_change, - owner_is_umask); - if (ret) { - cgroup_warn("Warning: cannot change file mode %s: %s\n", - fts_path, strerror(errno)); - last_errno = errno; - final_ret = ECGOTHER; - } - } - fts_close(fts); - return final_ret; -} - -int cg_chmod_recursive(struct cgroup *cgroup, mode_t dir_mode, - int dirm_change, mode_t file_mode, int filem_change) -{ - int i; - char *path; - int final_ret = 0; - int ret; - - path = malloc(FILENAME_MAX); - if (!path) { - last_errno = errno; - return ECGOTHER; - } - for (i = 0; i < cgroup->index; i++) { - if (!cg_build_path(cgroup->name, path, - cgroup->controller[i]->name)) { - final_ret = ECGFAIL; - break; - } - ret = cg_chmod_recursive_controller(path, dir_mode, dirm_change, - file_mode, filem_change, 0, NULL); - if (ret) - final_ret = ret; - } - free(path); - return final_ret; -} - -void cgroup_set_permissions(struct cgroup *cgroup, - mode_t control_dperm, mode_t control_fperm, - mode_t task_fperm) -{ - cgroup->control_dperm = control_dperm; - cgroup->control_fperm = control_fperm; - cgroup->task_fperm = task_fperm; -} - -static char *cgroup_basename(const char *path) -{ - char *base; - char *tmp_string; - - tmp_string = strdup(path); - - if (!tmp_string) - return NULL; - - base = strdup(basename(tmp_string)); - - free(tmp_string); - - return base; -} - -static int cgroup_test_subsys_mounted(const char *name) -{ - int i; - - pthread_rwlock_rdlock(&cg_mount_table_lock); - - for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { - if (strncmp(cg_mount_table[i].name, name, - sizeof(cg_mount_table[i].name)) == 0) { - pthread_rwlock_unlock(&cg_mount_table_lock); - return 1; - } - } - pthread_rwlock_unlock(&cg_mount_table_lock); - return 0; -} - -/** - * Free a single cgroup_rule struct. - * @param r The rule to free from memory - */ -static void cgroup_free_rule(struct cgroup_rule *r) -{ - /* Loop variable */ - int i = 0; - - /* Make sure our rule is not NULL, first. */ - if (!r) { - cgroup_warn("Warning: attempted to free NULL rule\n"); - return; - } - if (r->procname) { - free(r->procname); - r->procname = NULL; - } - /* We must free any used controller strings, too. */ - for (i = 0; i < MAX_MNT_ELEMENTS; i++) { - if (r->controllers[i]) - free(r->controllers[i]); - } - - free(r); -} - -/** - * Free a list of cgroup_rule structs. If rl is the main list of rules, - * the lock must be taken for writing before calling this function! - * @param rl Pointer to the list of rules to free from memory - */ -static void cgroup_free_rule_list(struct cgroup_rule_list *cg_rl) -{ - /* Temporary pointer */ - struct cgroup_rule *tmp = NULL; - - /* Make sure we're not freeing NULL memory! */ - if (!(cg_rl->head)) { - cgroup_warn("Warning: attempted to free NULL list\n"); - return; - } - - while (cg_rl->head) { - tmp = cg_rl->head; - cg_rl->head = tmp->next; - cgroup_free_rule(tmp); - } - - /* Don't leave wild pointers around! */ - cg_rl->head = NULL; - cg_rl->tail = NULL; -} - -static char *cg_skip_unused_charactors_in_rule(char *rule) -{ - char *itr; - - /* We ignore anything after a # sign as comments. */ - itr = strchr(rule, '#'); - if (itr) - *itr = '\0'; - - /* We also need to remove the newline character. */ - itr = strchr(rule, '\n'); - if (itr) - *itr = '\0'; - - /* Now, skip any leading tabs and spaces. */ - itr = rule; - while (itr && isblank(*itr)) - itr++; - - /* If there's nothing left, we can ignore this line. */ - if (!strlen(itr)) - return NULL; - - return itr; -} - -/** - * Parse the options field in the rule from the cgrules configuration file - * - * @param options Comma-separated string of options - * @param rule Rule that will contain the parsed options - * @return 0 on success, -EINVAL if the options are invalid - * TODO: Make this function thread safe! - * - */ -STATIC int cgroup_parse_rules_options(char *options, - struct cgroup_rule * const rule) -{ - char *stok_buff = NULL; - size_t cmp_len; - int ret = 0; - - stok_buff = strtok(options, ","); - if (!stok_buff) { - cgroup_err("Error: failed to parse options: %s\n", - options); - return -EINVAL; - } - - do { - cmp_len = min(strlen(stok_buff), strlen(CGRULE_OPTION_IGNORE)); - if (strlen(stok_buff) == strlen(CGRULE_OPTION_IGNORE) && - strncmp(stok_buff, CGRULE_OPTION_IGNORE, cmp_len) == 0) { - rule->is_ignore = true; - continue; - } - - /* - * "ignore" is the only currently supported option. raise - * an error if we get here - */ - cgroup_err("Error: Unsupported option: %s\n", stok_buff); - ret = -EINVAL; - break; - } while ((stok_buff = strtok(NULL, ","))); - - return ret; -} -/** - * Parse the configuration file that maps UID/GIDs to cgroups. If ever the - * configuration file is modified, applications should call this function to - * load the new configuration rules. The function caller is responsible for - * calling free() on each rule in the list. - * - * The cache parameter alters the behavior of this function. If true, this - * function will read the entire configuration file and store the results in - * rl (global rules list). If false, this function will only parse until it - * finds a rule matching the given UID or GID. It will store this rule in trl, - * as well as any children rules (rules that begin with a %) that it has. - * - * This function is NOT thread safe! - * @param filename configuration file to parse - * @param cache True to cache rules, else false - * @param muid If cache is false, the UID to match against - * @param mgid If cache is false, the GID to match against - * @return 0 on success, -1 if no cache and match found, > 0 on error. - * TODO: Make this function thread safe! - * - */ -static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid, - gid_t mgid, const char *mprocname) -{ - /* File descriptor for the configuration file */ - FILE *fp = NULL; - - /* Buffer to store the line we're working on */ - char buff[CGROUP_RULE_MAXLINE] = { '\0' }; - - /* Iterator for the line we're working on */ - char *itr = NULL; - - /* Pointer to process name in a line of the configuration file */ - char *procname = NULL; - - /* Pointer to the list that we're using */ - struct cgroup_rule_list *lst = NULL; - - /* Rule to add to the list */ - struct cgroup_rule *newrule = NULL; - - /* Structure to get GID from group name */ - struct group *grp = NULL; - - /* Structure to get UID from user name */ - struct passwd *pwd = NULL; - - /* Temporary storage for a configuration rule */ - char key[CGROUP_RULE_MAXKEY] = { '\0' }; - char user[LOGIN_NAME_MAX] = { '\0' }; - char controllers[CG_CONTROLLER_MAX] = { '\0' }; - char destination[FILENAME_MAX] = { '\0' }; - char options[CG_OPTIONS_MAX] = { '\0' }; - uid_t uid = CGRULE_INVALID; - gid_t gid = CGRULE_INVALID; - size_t len_username; - int len_procname; - bool has_options = false; - - /* The current line number */ - unsigned int linenum = 0; - - /* Did we skip the previous line? */ - bool skipped = false; - - /* Have we found a matching rule (non-cache mode)? */ - bool matched = false; - - /* Return codes */ - int ret = 0; - - /* Temporary buffer for strtok() */ - char *stok_buff = NULL; - - /* Loop variable. */ - int i = 0; - - /* Determine which list we're using. */ - if (cache) - lst = &rl; - else - lst = &trl; - - /* Open the configuration file. */ - fp = fopen(filename, "re"); - if (!fp) { - cgroup_warn("Warning: failed to open configuration file %s: %s\n", - filename, strerror(errno)); - - ret = ECGRULESPARSEFAIL; /* originally ret = 0, but */ - /* this is parse fail, not success */ - goto finish; - } - - /* Now, parse the configuration file one line at a time. */ - cgroup_dbg("Parsing configuration file %s.\n", filename); - while (fgets(buff, sizeof(buff), fp) != NULL) { - linenum++; - - itr = cg_skip_unused_charactors_in_rule(buff); - if (!itr) - continue; - - /* - * If we skipped the last rule and this rule is a continuation - * of it (begins with %), then we should skip this rule too. - */ - if (skipped && *itr == '%') { - cgroup_warn("Warning: skipped child of invalid rule," - " line %d.\n", linenum); - continue; - } - - /* - * If there is something left, it should be a rule. Otherwise, - * there's an error in the configuration file. - */ - skipped = false; - i = sscanf(itr, "%s%s%s%s", key, controllers, destination, - options); - if (i < 3) { - cgroup_err( - "Error: failed to parse configuration file on line %d\n", - linenum); - goto parsefail; - } else if (i == 3) { - has_options = false; - } else if (i == 4) { - has_options = true; - } - - procname = strchr(key, ':'); - if (procname) { - /* : */ - procname++; /* skip ':' */ - len_username = procname - key - 1; - len_procname = strlen(procname); - if (len_procname < 0) { - cgroup_err( - "Error: failed to parse configuration file on line %d\n", - linenum); - goto parsefail; - } - } else { - len_username = strlen(key); - len_procname = 0; - } - len_username = min(len_username, sizeof(user) - 1); - memset(user, '\0', sizeof(user)); - strncpy(user, key, len_username); - - /* - * Next, check the user/group. If it's a % sign, then we - * are continuing another rule and UID/GID should not be - * reset. If it's a @, we're dealing with a GID rule. If - * it's a *, then we do not need to do a lookup because the - * rule always applies (it's a wildcard). If we're using - * non-cache mode and we've found a matching rule, we only - * continue to parse if we're looking at a child rule. - */ - if ((!cache) && matched && (strncmp(user, "%", 1) != 0)) { - /* If we make it here, we finished (non-cache). */ - cgroup_dbg("Parsing of configuration file" - " complete.\n\n"); - ret = -1; - goto close; - } - if (strncmp(user, "@", 1) == 0) { - /* New GID rule. */ - itr = &(user[1]); - grp = getgrnam(itr); - if (grp) { - uid = CGRULE_INVALID; - gid = grp->gr_gid; - } else { - cgroup_warn("Warning: Entry for %s not" - "found. Skipping rule on line" - " %d.\n", itr, linenum); - skipped = true; - continue; - } - } else if (strncmp(user, "*", 1) == 0) { - /* Special wildcard rule. */ - uid = CGRULE_WILD; - gid = CGRULE_WILD; - } else if (*itr != '%') { - /* New UID rule. */ - pwd = getpwnam(user); - if (pwd) { - uid = pwd->pw_uid; - gid = CGRULE_INVALID; - } else { - cgroup_warn("Warning: Entry for %s not" - "found. Skipping rule on line" - " %d.\n", user, linenum); - skipped = true; - continue; - } - } /* Else, we're continuing another rule (UID/GID are okay). */ - - /* - * If we are not caching rules, then we need to check for a - * match before doing anything else. We consider four cases: - * The UID matches, the GID matches, the UID is a member of the - * GID, or we're looking at the wildcard rule, which always - * matches. If none of these are true, we simply continue to - * the next line in the file. - */ - if (grp && muid != CGRULE_INVALID) { - pwd = getpwuid(muid); - if (!pwd) { - continue; - } - for (i = 0; grp->gr_mem[i]; i++) { - if (!(strcmp(pwd->pw_name, grp->gr_mem[i]))) - matched = true; - } - } - - if (uid == muid || gid == mgid || uid == CGRULE_WILD) - matched = true; - - if (!cache) { - if (!matched) - continue; - if (len_procname) { - char *mproc_base; - /* - * If there is a rule based on process name, - * it should be matched with mprocname. - */ - if (!mprocname) { - uid = CGRULE_INVALID; - gid = CGRULE_INVALID; - matched = false; - continue; - } - - mproc_base = cgroup_basename(mprocname); - if (strcmp(mprocname, procname) && - strcmp(mproc_base, procname)) { - uid = CGRULE_INVALID; - gid = CGRULE_INVALID; - matched = false; - free(mproc_base); - continue; - } - free(mproc_base); - } - } - - /* - * Now, we're either caching rules or we found a match. Either - * way, copy everything into a new rule and push it into the - * list. - */ - newrule = calloc(1, sizeof(struct cgroup_rule)); - if (!newrule) { - cgroup_err("Error: out of memory? Error was: %s\n", - strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - goto close; - } - - newrule->uid = uid; - newrule->gid = gid; - newrule->is_ignore = false; - len_username = min(len_username, - sizeof(newrule->username) - 1); - strncpy(newrule->username, user, len_username); - if (len_procname) { - newrule->procname = strdup(procname); - if (!newrule->procname) { - cgroup_err("Error: strdup failed to allocate memory %s\n", - strerror(errno)); - free(newrule); - last_errno = errno; - ret = ECGOTHER; - goto close; - } - } else { - newrule->procname = NULL; - } - strncpy(newrule->destination, destination, - sizeof(newrule->destination) - 1); - - if (has_options) { - ret = cgroup_parse_rules_options(options, newrule); - if (ret < 0) - goto destroyrule; - } - - newrule->next = NULL; - - /* Parse the controller list, and add that to newrule too. */ - stok_buff = strtok(controllers, ","); - if (!stok_buff) { - cgroup_err("Error: failed to parse controllers on line %d\n", - linenum); - goto destroyrule; - } - - i = 0; - do { - if (i >= MAX_MNT_ELEMENTS) { - cgroup_err("Error: too many controllers listed on line %d\n", - linenum); - goto destroyrule; - } - - newrule->controllers[i] = strndup(stok_buff, - strlen(stok_buff) + 1); - if (!(newrule->controllers[i])) { - cgroup_err("Error: out of memory? Error was: %s\n", - strerror(errno)); - goto destroyrule; - } - i++; - } while ((stok_buff = strtok(NULL, ","))); - - /* Now, push the rule. */ - if (lst->head == NULL) { - lst->head = newrule; - lst->tail = newrule; - } else { - lst->tail->next = newrule; - lst->tail = newrule; - } - - cgroup_dbg("Added rule %s (UID: %d, GID: %d) -> %s for" - " controllers:", lst->tail->username, lst->tail->uid, - lst->tail->gid, lst->tail->destination); - for (i = 0; lst->tail->controllers[i]; i++) - cgroup_dbg(" %s", lst->tail->controllers[i]); - cgroup_dbg("\n"); - - /* Finally, clear the buffer. */ - grp = NULL; - pwd = NULL; - } - - /* If we make it here, there were no errors. */ - cgroup_dbg("Parsing of configuration file complete.\n\n"); - ret = (matched && !cache) ? -1 : 0; - goto close; - -destroyrule: - cgroup_free_rule(newrule); - -parsefail: - ret = ECGRULESPARSEFAIL; - -close: - fclose(fp); -finish: - return ret; -} - -/** - * Parse CGRULES_CONF_FILE and all files in CGRULES_CONF_FILE_DIR. - * If CGRULES_CONF_FILE_DIR does not exists or can not be read, - * parse only CGRULES_CONF_FILE. This way we keep the back compatibility. - * - * Original description of this function moved to cgroup_parse_rules_file. - * Also cloned and all occurences of file changed to files. - * - * Parse the configuration files that maps UID/GIDs to cgroups. If ever the - * configuration files are modified, applications should call this function to - * load the new configuration rules. The function caller is responsible for - * calling free() on each rule in the list. - * - * The cache parameter alters the behavior of this function. If true, this - * function will read the entire content of all configuration files and store - * the results in rl (global rules list). If false, this function will only - * parse until it finds a file and a rule matching the given UID or GID. - * The remaining files are skipped. It will store this rule in trl, - * as well as any children rules (rules that begin with a %) that it has. - * - * Files can be read in an random order so the first match must not be - * dependent on it. Thus construct the rules the way not to break - * this assumption. - * - * This function is NOT thread safe! - * @param cache True to cache rules, else false - * @param muid If cache is false, the UID to match against - * @param mgid If cache is false, the GID to match against - * @return 0 on success, -1 if no cache and match found, > 0 on error. - * TODO: Make this function thread safe! - */ -static int cgroup_parse_rules(bool cache, uid_t muid, - gid_t mgid, const char *mprocname) -{ - int ret; - - /* Pointer to the list that we're using */ - struct cgroup_rule_list *lst = NULL; - - /* Directory variables */ - DIR *d; - struct dirent *item; - const char *dirname = CGRULES_CONF_DIR; - char *tmp; - int sret; - - /* Determine which list we're using. */ - if (cache) - lst = &rl; - else - lst = &trl; - - /* If our list already exists, clean it. */ - if (lst->head) - cgroup_free_rule_list(lst); - - pthread_rwlock_wrlock(&rl_lock); - - /* Parse CGRULES_CONF_FILE configuration file (back compatibility). */ - ret = cgroup_parse_rules_file(CGRULES_CONF_FILE, - cache, muid, mgid, mprocname); - - /* - * if match (ret = -1), stop parsing other files, just return - * or ret > 0 => error - */ - if (ret != 0) { - pthread_rwlock_unlock(&rl_lock); - return ret; - } - - /* Continue parsing */ - d = opendir(dirname); - if (!d) { - cgroup_warn("Warning: Failed to open directory %s: %s\n", - dirname, strerror(errno)); - - /* - * Cannot read directory. However, CGRULES_CONF_FILE is - * succesfully parsed. Thus return as a success - * for back compatibility. - */ - pthread_rwlock_unlock(&rl_lock); - - return 0; - } - - /* read all files from CGRULES_CONF_FILE_DIR */ - do { - item = readdir(d); - if (item && (item->d_type == DT_REG - || item->d_type == DT_LNK)) { - - sret = asprintf(&tmp, "%s/%s", dirname, item->d_name); - if (sret < 0) { - cgroup_err("Out of memory\n"); - - /* - * Cannot read directory. However, CGRULES_CONF_FILE is - * succesfully parsed. Thus return as a success - * for back compatibility. - */ - ret = 0; - goto unlock_list; - } - - cgroup_dbg("Parsing cgrules file: %s\n", tmp); - ret = cgroup_parse_rules_file(tmp, - cache, muid, mgid, mprocname); - - free(tmp); - - /* match with cache disabled? */ - if (ret != 0) - goto unlock_list; - } - if (!item && errno) { - cgroup_warn("Warning: cannot read %s: %s\n", - dirname, strerror(errno)); - /* - * Cannot read an item. But continue for - * back compatibility as a success. - */ - ret = 0; - goto unlock_list; - } - } while (item != NULL); - -unlock_list: - closedir(d); - - pthread_rwlock_unlock(&rl_lock); - - return ret; -} - -int cg_add_duplicate_mount(struct cg_mount_table_s *item, const char *path) -{ - struct cg_mount_point *mount, *it; - - mount = malloc(sizeof(struct cg_mount_point)); - if (!mount) { - last_errno = errno; - return ECGOTHER; - } - mount->next = NULL; - strncpy(mount->path, path, sizeof(mount->path)); - mount->path[sizeof(mount->path)-1] = '\0'; - - /* - * Add the mount point to the end of the list. - * Assuming the list is short, no optimization is done. - */ - it = &item->mount; - while (it->next) - it = it->next; - - it->next = mount; - return 0; -} - -/** - * cgroup_init(), initializes the MOUNT_POINT. - * - * This code is theoretically thread safe now. Its not really tested - * so it can blow up. If does for you, please let us know with your - * test case and we can really make it thread safe. - * - */ -int cgroup_init(void) -{ - FILE *proc_mount = NULL; - struct mntent *ent = NULL; - struct mntent *temp_ent = NULL; - int found_mnt = 0; - int ret = 0; - static char *controllers[CG_CONTROLLER_MAX]; - FILE *proc_cgroup = NULL; - char subsys_name[FILENAME_MAX]; - int hierarchy, num_cgroups, enabled; - int i = 0; - int j; - int duplicate = 0; - char *mntopt = NULL; - int err; - char *buf = NULL; - char mntent_buffer[4 * FILENAME_MAX]; - char *strtok_buffer = NULL; - - cgroup_set_default_logger(-1); - - pthread_rwlock_wrlock(&cg_mount_table_lock); - - /* free global variables filled by previous cgroup_init() */ - for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { - struct cg_mount_point *mount = cg_mount_table[i].mount.next; - while (mount) { - struct cg_mount_point *tmp = mount; - mount = mount->next; - free(tmp); - } - } - memset(&cg_mount_table, 0, sizeof(cg_mount_table)); - - proc_cgroup = fopen("/proc/cgroups", "re"); - - if (!proc_cgroup) { - cgroup_err("Error: cannot open /proc/cgroups: %s\n", - strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - goto unlock_exit; - } - - /* - * The first line of the file has stuff we are not interested in. - * So just read it and discard the information. - * - * XX: fix the size for fgets - */ - buf = malloc(FILENAME_MAX); - if (!buf) { - last_errno = errno; - ret = ECGOTHER; - goto unlock_exit; - } - if (!fgets(buf, FILENAME_MAX, proc_cgroup)) { - free(buf); - cgroup_err("Error: cannot read /proc/cgroups: %s\n", - strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - goto unlock_exit; - } - free(buf); - - i = 0; - while (!feof(proc_cgroup)) { - err = fscanf(proc_cgroup, "%s %d %d %d", subsys_name, - &hierarchy, &num_cgroups, &enabled); - if (err < 0) - break; - controllers[i] = strdup(subsys_name); - i++; - } - controllers[i] = NULL; - - proc_mount = fopen("/proc/mounts", "re"); - if (proc_mount == NULL) { - cgroup_err("Error: cannot open /proc/mounts: %s\n", - strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - goto unlock_exit; - } - - temp_ent = (struct mntent *) malloc(sizeof(struct mntent)); - - if (!temp_ent) { - last_errno = errno; - ret = ECGOTHER; - goto unlock_exit; - } - - while ((ent = getmntent_r(proc_mount, temp_ent, - mntent_buffer, - sizeof(mntent_buffer))) != NULL) { - if (strcmp(ent->mnt_type, "cgroup")) - continue; - - for (i = 0; controllers[i] != NULL; i++) { - mntopt = hasmntopt(ent, controllers[i]); - - if (!mntopt) - continue; - - cgroup_dbg("found %s in %s\n", controllers[i], ent->mnt_opts); - - /* do not have duplicates in mount table */ - duplicate = 0; - for (j = 0; j < found_mnt; j++) { - if (strncmp(controllers[i], - cg_mount_table[j].name, - FILENAME_MAX) == 0) { - duplicate = 1; - break; - } - } - if (duplicate) { - cgroup_dbg("controller %s is already mounted on %s\n", - mntopt, cg_mount_table[j].mount.path); - ret = cg_add_duplicate_mount(&cg_mount_table[j], - ent->mnt_dir); - if (ret) - goto unlock_exit; - /* continue with next controller */ - continue; - } - - strncpy(cg_mount_table[found_mnt].name, - controllers[i], FILENAME_MAX); - cg_mount_table[found_mnt].name[FILENAME_MAX-1] = '\0'; - strncpy(cg_mount_table[found_mnt].mount.path, - ent->mnt_dir, FILENAME_MAX); - cg_mount_table[found_mnt].mount.path[FILENAME_MAX-1] = - '\0'; - cg_mount_table[found_mnt].mount.next = NULL; - cgroup_dbg("Found cgroup option %s, count %d\n", - ent->mnt_opts, found_mnt); - found_mnt++; - } - - /* - * Doesn't match the controller. - * Check if it is a named hierarchy. - */ - mntopt = hasmntopt(ent, "name"); - - if (mntopt) { - mntopt = strtok_r(mntopt, ",", &strtok_buffer); - if (!mntopt) - continue; - /* - * Check if it is a duplicate - */ - duplicate = 0; - -#ifdef OPAQUE_HIERARCHY - /* - * Ignore the opaque hierarchy. - */ - if (strcmp(mntopt, OPAQUE_HIERARCHY) == 0) - continue; -#endif - - for (j = 0; j < found_mnt; j++) { - if (strncmp(mntopt, cg_mount_table[j].name, - FILENAME_MAX) == 0) { - duplicate = 1; - break; - } - } - - if (duplicate) { - cgroup_dbg("controller %s is already mounted on %s\n", - mntopt, cg_mount_table[j].mount.path); - ret = cg_add_duplicate_mount(&cg_mount_table[j], - ent->mnt_dir); - if (ret) - goto unlock_exit; - continue; - } - - strncpy(cg_mount_table[found_mnt].name, - mntopt, FILENAME_MAX); - cg_mount_table[found_mnt].name[FILENAME_MAX-1] = '\0'; - strncpy(cg_mount_table[found_mnt].mount.path, - ent->mnt_dir, FILENAME_MAX); - cg_mount_table[found_mnt].mount.path[FILENAME_MAX-1] = - '\0'; - cg_mount_table[found_mnt].mount.next = NULL; - cgroup_dbg("Found cgroup option %s, count %d\n", - ent->mnt_opts, found_mnt); - found_mnt++; - } - } - - free(temp_ent); - - if (!found_mnt) { - cg_mount_table[0].name[0] = '\0'; - ret = ECGROUPNOTMOUNTED; - goto unlock_exit; - } - - found_mnt++; - cg_mount_table[found_mnt].name[0] = '\0'; - - cgroup_initialized = 1; - -unlock_exit: - if (proc_cgroup) - fclose(proc_cgroup); - - if (proc_mount) - fclose(proc_mount); - - for (i = 0; controllers[i]; i++) { - free(controllers[i]); - controllers[i] = NULL; - } - - pthread_rwlock_unlock(&cg_mount_table_lock); - - return ret; -} - -static int cg_test_mounted_fs(void) -{ - FILE *proc_mount = NULL; - struct mntent *ent = NULL; - struct mntent *temp_ent = NULL; - char mntent_buff[4 * FILENAME_MAX]; - int ret = 1; - - proc_mount = fopen("/proc/mounts", "re"); - if (proc_mount == NULL) - return 0; - - temp_ent = (struct mntent *) malloc(sizeof(struct mntent)); - if (!temp_ent) { - /* We just fail at the moment. */ - fclose(proc_mount); - return 0; - } - - ent = getmntent_r(proc_mount, temp_ent, mntent_buff, - sizeof(mntent_buff)); - - if (!ent) { - ret = 0; - goto done; - } - - while (strcmp(ent->mnt_type, "cgroup") != 0) { - ent = getmntent_r(proc_mount, temp_ent, mntent_buff, - sizeof(mntent_buff)); - if (ent == NULL) { - ret = 0; - goto done; - } - } -done: - fclose(proc_mount); - free(temp_ent); - return ret; -} - -static inline pid_t cg_gettid(void) -{ - return syscall(__NR_gettid); -} - -static char *cg_concat_path(const char *pref, const char *suf, char *path) -{ - if ((suf[strlen(suf)-1] == '/') || - ((strlen(suf) == 0) && (pref[strlen(pref)-1] == '/'))) { - snprintf(path, FILENAME_MAX, "%s%s", pref, - suf+((suf[0] == '/') ? 1 : 0)); - } else { - snprintf(path, FILENAME_MAX, "%s%s/", pref, - suf+((suf[0] == '/') ? 1 : 0)); - } - path[FILENAME_MAX-1] = '\0'; - return path; -} - - -/* Call with cg_mount_table_lock taken */ -/* path value have to have size at least FILENAME_MAX */ -static char *cg_build_path_locked(const char *name, char *path, - const char *type) -{ - int i; - for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { - if (strcmp(cg_mount_table[i].name, type) == 0) { - if (cg_namespace_table[i]) { - snprintf(path, FILENAME_MAX, "%s/%s/", - cg_mount_table[i].mount.path, - cg_namespace_table[i]); - path[FILENAME_MAX-1] = '\0'; - } else { - snprintf(path, FILENAME_MAX, "%s/", - cg_mount_table[i].mount.path); - path[FILENAME_MAX-1] = '\0'; - } - - if (name) { - char *tmp; - tmp = strdup(path); - - /* FIXME: missing OOM check here! */ - - cg_concat_path(tmp, name, path); - free(tmp); - } - return path; - } - } - return NULL; -} - -char *cg_build_path(const char *name, char *path, const char *type) -{ - pthread_rwlock_rdlock(&cg_mount_table_lock); - path = cg_build_path_locked(name, path, type); - pthread_rwlock_unlock(&cg_mount_table_lock); - - return path; -} - -static int __cgroup_attach_task_pid(char *path, pid_t tid) -{ - int ret = 0; - FILE *tasks = NULL; - - tasks = fopen(path, "we"); - if (!tasks) { - switch (errno) { - case EPERM: - ret = ECGROUPNOTOWNER; - break; - case ENOENT: - ret = ECGROUPNOTEXIST; - break; - default: - ret = ECGROUPNOTALLOWED; - } - goto err; - } - ret = fprintf(tasks, "%d", tid); - if (ret < 0) { - last_errno = errno; - ret = ECGOTHER; - goto err; - } - ret = fflush(tasks); - if (ret) { - last_errno = errno; - ret = ECGOTHER; - goto err; - } - fclose(tasks); - return 0; -err: - cgroup_warn("Warning: cannot write tid %d to %s:%s\n", - tid, path, strerror(errno)); - if (tasks) - fclose(tasks); - return ret; -} - -/** cgroup_attach_task_pid is used to assign tasks to a cgroup. - * struct cgroup *cgroup: The cgroup to assign the thread to. - * pid_t tid: The thread to be assigned to the cgroup. - * - * returns 0 on success. - * returns ECGROUPNOTOWNER if the caller does not have access to the cgroup. - * returns ECGROUPNOTALLOWED for other causes of failure. - */ -int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) -{ - char path[FILENAME_MAX]; - int i, ret = 0; - - if (!cgroup_initialized) { - cgroup_warn("Warning: libcgroup is not initialized\n"); - return ECGROUPNOTINITIALIZED; - } - if (!cgroup) { - pthread_rwlock_rdlock(&cg_mount_table_lock); - for (i = 0; i < CG_CONTROLLER_MAX && - cg_mount_table[i].name[0] != '\0'; i++) { - if (!cg_build_path_locked(NULL, path, - cg_mount_table[i].name)) - continue; - strncat(path, "/tasks", sizeof(path) - strlen(path)); - ret = __cgroup_attach_task_pid(path, tid); - if (ret) { - pthread_rwlock_unlock(&cg_mount_table_lock); - return ret; - } - } - pthread_rwlock_unlock(&cg_mount_table_lock); - } else { - for (i = 0; i < cgroup->index; i++) { - if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) { - cgroup_warn("Warning: subsystem %s is not mounted\n", - cgroup->controller[i]->name); - return ECGROUPSUBSYSNOTMOUNTED; - } - } - - for (i = 0; i < cgroup->index; i++) { - if (!cg_build_path(cgroup->name, path, - cgroup->controller[i]->name)) - continue; - strncat(path, "/tasks", sizeof(path) - strlen(path)); - ret = __cgroup_attach_task_pid(path, tid); - if (ret) - return ret; - } - } - return 0; -} - -/** cgroup_attach_task is used to attach the current thread to a cgroup. - * struct cgroup *cgroup: The cgroup to assign the current thread to. - * - * See cg_attach_task_pid for return values. - */ -int cgroup_attach_task(struct cgroup *cgroup) -{ - pid_t tid = cg_gettid(); - int error; - - error = cgroup_attach_task_pid(cgroup, tid); - - return error; -} - -/** - * cg_mkdir_p, emulate the mkdir -p command (recursively creating paths) - * @path: path to create - */ -int cg_mkdir_p(const char *path) -{ - char *real_path = NULL; - int i = 0; - char pos; - int ret = 0, stat_ret; - struct stat st; - - real_path = strdup(path); - if (!real_path) { - last_errno = errno; - return ECGOTHER; - } - - do { - while (real_path[i] != '\0' && real_path[i] == '/') - i++; - if (real_path[i] == '\0') - break; /* The path ends with '/', ignore it. */ - while (real_path[i] != '\0' && real_path[i] != '/') - i++; - pos = real_path[i]; - real_path[i] = '\0'; /* Temporarily overwrite "/" */ - ret = mkdir(real_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - real_path[i] = pos; - if (ret) { - switch (errno) { - case EEXIST: - ret = 0; /* Not fatal really */ - break; - case EPERM: - ret = ECGROUPNOTOWNER; - goto done; - default: - /* Check if path exists */ - real_path[i] = '\0'; - stat_ret = stat(real_path, &st); - real_path[i] = pos; - if (stat_ret == 0) { - ret = 0; /* Path exists */ - break; - } - ret = ECGROUPNOTALLOWED; - goto done; - } - } - } while (real_path[i]); - -done: - free(real_path); - return ret; -} - -/* - * create_control_group() - * This is the basic function used to create the control group. This function - * just makes the group. It does not set any permissions, or any control values. - * The argument path is the fully qualified path name to make it generic. - */ -static int cg_create_control_group(const char *path) -{ - int error; - if (!cg_test_mounted_fs()) - return ECGROUPNOTMOUNTED; - error = cg_mkdir_p(path); - return error; -} - -/* - * set_control_value() - * This is the low level function for putting in a value in a control file. - * This function takes in the complete path and sets the value in val in that - * file. - */ -static int cg_set_control_value(char *path, const char *val) -{ - int ctl_file; - char *str_val; - char *str_val_start; - char *pos; - size_t len; - - if (!cg_test_mounted_fs()) - return ECGROUPNOTMOUNTED; - - ctl_file = open(path, O_RDWR | O_CLOEXEC); - - if (ctl_file == -1) { - if (errno == EPERM) { - /* - * We need to set the correct error value, does the - * group exist but we don't have the subsystem - * mounted at that point, or is it that the group - * does not exist. So we check if the tasks file - * exist. Before that, we need to extract the path. - */ - char *path_dir_end; - char *tasks_path; - FILE *control_file; - - path_dir_end = strrchr(path, '/'); - if (path_dir_end == NULL) - return ECGROUPVALUENOTEXIST; - path_dir_end = '\0'; - - /* task_path contain: $path/tasks */ - tasks_path = (char *)malloc(strlen(path) + 6 + 1); - if (tasks_path == NULL) { - last_errno = errno; - return ECGOTHER; - } - strcpy(tasks_path, path); - strcat(tasks_path, "/tasks"); - - /* test tasks file for read flag */ - control_file = fopen(tasks_path, "re"); - if (!control_file) { - if (errno == ENOENT) { - free(tasks_path); - return ECGROUPSUBSYSNOTMOUNTED; - } - } else { - fclose(control_file); - } - free(tasks_path); - return ECGROUPNOTALLOWED; - } - return ECGROUPVALUENOTEXIST; - } - - /* Split the multiline value into lines. */ - /* One line is a special case of multiline value. */ - str_val = strdup(val); - if (str_val == NULL) { - last_errno = errno; - close(ctl_file); - return ECGOTHER; - } - - str_val_start = str_val; - pos = str_val; - - do { - str_val = pos; - pos = strchr(str_val, '\n'); - - if (pos) { - *pos = '\0'; - ++pos; - } - - len = strlen(str_val); - if (len > 0) { - if (write(ctl_file, str_val, len) == -1) { - last_errno = errno; - free(str_val_start); - close(ctl_file); - return ECGOTHER; - } - } else - cgroup_warn("Warning: skipping empty line for %s\n", - path); - } while(pos); - - if (close(ctl_file)) { - last_errno = errno; - free(str_val_start); - return ECGOTHER; - } - - free(str_val_start); - return 0; -} - -/** cgroup_modify_cgroup modifies the cgroup control files. - * struct cgroup *cgroup: The name will be the cgroup to be modified. - * The values will be the values to be modified, those not mentioned - * in the structure will not be modified. - * - * The uids cannot be modified yet. - * - * returns 0 on success. - * - */ - -int cgroup_modify_cgroup(struct cgroup *cgroup) -{ - char *path, base[FILENAME_MAX]; - int i; - int error = 0; - int ret; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!cgroup) - return ECGROUPNOTALLOWED; - - for (i = 0; i < cgroup->index; i++) { - if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) { - cgroup_warn("Warning: subsystem %s is not mounted\n", - cgroup->controller[i]->name); - return ECGROUPSUBSYSNOTMOUNTED; - } - } - - for (i = 0; i < cgroup->index; i++) { - int j; - if (!cg_build_path(cgroup->name, base, - cgroup->controller[i]->name)) - continue; - for (j = 0; j < cgroup->controller[i]->index; j++) { - ret = asprintf(&path, "%s%s", base, - cgroup->controller[i]->values[j]->name); - if (ret < 0) { - last_errno = errno; - error = ECGOTHER; - goto err; - } - error = cg_set_control_value(path, - cgroup->controller[i]->values[j]->value); - free(path); - path = NULL; - /* don't consider error in files directly written by - * the user as fatal */ - if (error && !cgroup->controller[i]->values[j]->dirty) { - error = 0; - continue; - } - if (error) - goto err; - cgroup->controller[i]->values[j]->dirty = false; - } - } -err: - return error; - -} - -/** - * @dst: Destination controller - * @src: Source controller from which values will be copied to dst - * - * Create a duplicate copy of values under the specified controller - */ -static int cgroup_copy_controller_values(struct cgroup_controller *dst, - struct cgroup_controller *src) -{ - int i, ret = 0; - - if (!dst || !src) - return ECGFAIL; - - strncpy(dst->name, src->name, FILENAME_MAX); - for (i = 0; i < src->index; i++, dst->index++) { - struct control_value *src_val = src->values[i]; - struct control_value *dst_val; - - dst->values[i] = calloc(1, sizeof(struct control_value)); - if (!dst->values[i]) { - last_errno = errno; - ret = ECGOTHER; - goto err; - } - - dst_val = dst->values[i]; - strncpy(dst_val->value, src_val->value, CG_CONTROL_VALUE_MAX); - strncpy(dst_val->name, src_val->name, FILENAME_MAX); - dst_val->dirty = src_val->dirty; - } -err: - return ret; -} - -/** - * @dst: Destination control group - * @src: Source from which values will be copied to dst - * - * Create a duplicate copy of src in dst. This will be useful for those who - * that intend to create new instances based on an existing control group - */ -int cgroup_copy_cgroup(struct cgroup *dst, struct cgroup *src) -{ - int ret = 0, i; - - if (!dst || !src) - return ECGROUPNOTEXIST; - - /* - * Should we just use the restrict keyword instead? - */ - if (dst == src) - return ECGFAIL; - - cgroup_free_controllers(dst); - - for (i = 0; i < src->index; i++, dst->index++) { - struct cgroup_controller *src_ctlr = src->controller[i]; - struct cgroup_controller *dst_ctlr; - - dst->controller[i] = calloc(1, sizeof(struct cgroup_controller)); - if (!dst->controller[i]) { - last_errno = errno; - ret = ECGOTHER; - goto err; - } - - dst_ctlr = dst->controller[i]; - ret = cgroup_copy_controller_values(dst_ctlr, src_ctlr); - if (ret) - goto err; - } -err: - return ret; -} - -/** cgroup_create_cgroup creates a new control group. - * struct cgroup *cgroup: The control group to be created - * - * returns 0 on success. We recommend calling cg_delete_cgroup - * if this routine fails. That should do the cleanup operation. - * If ECGCANTSETVALUE is returned, the group was created successfully - * but not all controller parameters were successfully set. - */ -int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) -{ - char *fts_path[2]; - char *base = NULL; - char *path = NULL; - int i, j, k; - int error = 0; - int retval = 0; - int ret; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!cgroup) - return ECGROUPNOTALLOWED; - - for (i = 0; i < cgroup->index; i++) { - if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) - return ECGROUPSUBSYSNOTMOUNTED; - } - - fts_path[0] = (char *)malloc(FILENAME_MAX); - if (!fts_path[0]) { - last_errno = errno; - return ECGOTHER; - } - fts_path[1] = NULL; - path = fts_path[0]; - - /* - * XX: One important test to be done is to check, if you have multiple - * subsystems mounted at one point, all of them *have* be on the cgroup - * data structure. If not, we fail. - */ - for (k = 0; k < cgroup->index; k++) { - if (!cg_build_path(cgroup->name, path, - cgroup->controller[k]->name)) - continue; - - error = cg_create_control_group(path); - if (error) - goto err; - - base = strdup(path); - - if (!base) { - last_errno = errno; - error = ECGOTHER; - goto err; - } - - if (!ignore_ownership) { - cgroup_dbg("Changing ownership of %s\n", fts_path[0]); - error = cg_chown_recursive(fts_path, - cgroup->control_uid, cgroup->control_gid); - if (!error) - error = cg_chmod_recursive_controller(fts_path[0], - cgroup->control_dperm, - cgroup->control_dperm != NO_PERMS, - cgroup->control_fperm, - cgroup->control_fperm != NO_PERMS, - 1, cgroup_ignored_tasks_files); - } - - if (error) - goto err; - - for (j = 0; j < cgroup->controller[k]->index; j++) { - ret = snprintf(path, FILENAME_MAX, "%s%s", base, - cgroup->controller[k]->values[j]->name); - cgroup_dbg("setting %s to \"%s\", pathlen %d\n", path, - cgroup->controller[k]->values[j]->value, ret); - if (ret < 0 || ret >= FILENAME_MAX) { - last_errno = errno; - error = ECGOTHER; - goto err; - } - error = cg_set_control_value(path, - cgroup->controller[k]->values[j]->value); - /* - * Should we undo, what we've done in the loops above? - * An error should not be treated as fatal, since we - * have several read-only files and several files that - * are only conditionally created in the child. - * - * A middle ground would be to track that there - * was an error and return a diagnostic value-- - * callers don't get context for the error, but can - * ignore it specifically if they wish. - */ - if (error) { - cgroup_err("Error: failed to set %s: %s\n", - path, cgroup_strerror(error)); - retval = ECGCANTSETVALUE; - continue; - } - } - - if (!ignore_ownership) { - ret = snprintf(path, FILENAME_MAX, "%s/tasks", base); - if (ret < 0 || ret >= FILENAME_MAX) { - last_errno = errno; - error = ECGOTHER; - goto err; - } - error = cg_chown(path, cgroup->tasks_uid, - cgroup->tasks_gid); - if (!error && cgroup->task_fperm != NO_PERMS) - error = cg_chmod_path(path, cgroup->task_fperm, - 1); - - if (error) { - last_errno = errno; - error = ECGOTHER; - goto err; - } - - } - free(base); - base = NULL; - } - -err: - if (path) - free(path); - if (base) - free(base); - if (retval && !error) - error = retval; - return error; -} - -/** - * Obtain the calculated parent name of specified cgroup; no validation - * of the existence of the child or parent group is performed. - * - * Given the path-like hierarchy of cgroup names, this function returns - * the dirname() of the cgroup name as the likely parent name; the caller - * is responsible for validating parent as appropriate. - * - * @param cgroup The cgroup to query for parent's name - * @param parent Output, name of parent's group, or NULL if the - * provided cgroup is the root group. - * Caller is responsible to free the returned string. - * @return 0 on success, > 0 on error - */ -static int cgroup_get_parent_name(struct cgroup *cgroup, char **parent) -{ - int ret = 0; - char *dir = NULL; - char *pdir = NULL; - - dir = strdup(cgroup->name); - if (!dir) { - last_errno = errno; - return ECGOTHER; - } - cgroup_dbg("group name is %s\n", dir); - - pdir = dirname(dir); - cgroup_dbg("parent's group name is %s\n", pdir); - - /* check for root group */ - if (strlen(cgroup->name) == 0 || !strcmp(cgroup->name, pdir)) { - cgroup_dbg("specified cgroup \"%s\" is root group\n", - cgroup->name); - *parent = NULL; - } - else { - *parent = strdup(pdir); - if (*parent == NULL) { - last_errno = errno; - ret = ECGOTHER; - } - } - free(dir); - - return ret; -} - -/** - * Find the parent of the specified directory. It returns the parent in - * hierarchy of given controller (the parent is usually name/.. unless name is - * a mount point. It is assumed both the cgroup (and, therefore, parent) - * already exist, and will fail otherwise. - * - * When namespaces are used, a group can have different parents for different - * controllers. - * - * @param cgroup The cgroup - * @param controller The controller - * @param parent Output, name of parent's group (if the group has parent) or - * NULL, if the provided cgroup is the root group and has no parent. - * Caller is responsible to free the returned string! - * @return 0 on success, >0 on error. - */ -static int cgroup_find_parent(struct cgroup *cgroup, char *controller, - char **parent) -{ - char child_path[FILENAME_MAX]; - char *parent_path = NULL; - struct stat stat_child, stat_parent; - int ret = 0; - - *parent = NULL; - - pthread_rwlock_rdlock(&cg_mount_table_lock); - if (!cg_build_path_locked(cgroup->name, child_path, controller)) { - pthread_rwlock_unlock(&cg_mount_table_lock); - return ECGFAIL; - } - pthread_rwlock_unlock(&cg_mount_table_lock); - - cgroup_dbg("path is %s\n", child_path); - - if (asprintf(&parent_path, "%s/..", child_path) < 0) - return ECGFAIL; - - cgroup_dbg("parent's name is %s\n", parent_path); - - if (stat(child_path, &stat_child) < 0) { - last_errno = errno; - ret = ECGOTHER; - goto free_parent; - } - - if (stat(parent_path, &stat_parent) < 0) { - last_errno = errno; - ret = ECGOTHER; - goto free_parent; - } - - /* - * Is the specified "name" a mount point? - */ - if (stat_parent.st_dev != stat_child.st_dev) { - *parent = NULL; - ret = 0; - cgroup_dbg("Parent is on different device\n"); - } else { - ret = cgroup_get_parent_name(cgroup, parent); - } - -free_parent: - free(parent_path); - return ret; -} - -/** - * @cgroup: cgroup data structure to be filled with parent values and then - * passed down for creation - * @ignore_ownership: Ignore doing a chown on the newly created cgroup - * @return 0 on success, > 0 on failure. If ECGCANTSETVALUE is returned, - * the group was created successfully, but not all controller parameters - * were copied from the parent successfully; unfortunately, this is expected... - */ -int cgroup_create_cgroup_from_parent(struct cgroup *cgroup, - int ignore_ownership) -{ - char *parent = NULL; - struct cgroup *parent_cgroup = NULL; - int ret = ECGFAIL; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - ret = cgroup_get_parent_name(cgroup, &parent); - if (ret) - return ret; - - if (parent == NULL) { - /* - * The group to create is root group! - * TODO: find better error code? - */ - return ECGFAIL; - } - - cgroup_dbg("parent is %s\n", parent); - parent_cgroup = cgroup_new_cgroup(parent); - if (!parent_cgroup) { - ret = ECGFAIL; - goto err_nomem; - } - - if (cgroup_get_cgroup(parent_cgroup)) { - ret = ECGFAIL; - goto err_parent; - } - - cgroup_dbg("got parent group for %s\n", parent_cgroup->name); - ret = cgroup_copy_cgroup(cgroup, parent_cgroup); - if (ret) { - goto err_parent; - } - - cgroup_dbg("copied parent group %s to %s\n", parent_cgroup->name, - cgroup->name); - ret = cgroup_create_cgroup(cgroup, ignore_ownership); - -err_parent: - cgroup_free(&parent_cgroup); -err_nomem: - free(parent); - return ret; -} - -/** - * Move all processes from one task file to another. - * @param input_tasks Pre-opened file to read tasks from. - * @param output_tasks Pre-opened file to write tasks to. - * @return 0 on succes, >0 on error. - */ -static int cg_move_task_files(FILE *input_tasks, FILE *output_tasks) -{ - int tids; - int ret = 0; - - while (!feof(input_tasks)) { - ret = fscanf(input_tasks, "%d", &tids); - if (ret == EOF || ret == 0) { - ret = 0; - break; - } - if (ret < 0) - break; - - ret = fprintf(output_tasks, "%d", tids); - if (ret < 0) { - if (errno == ESRCH) - ret = 0; - else - break; - } - - /* - * Flush the file, we need only one process per write() call. - */ - ret = fflush(output_tasks); - if (ret < 0) { - if (errno == ESRCH) - ret = 0; - else - break; - } - } - - if (ret < 0) { - last_errno = errno; - return ECGOTHER; - } - return 0; -} - -/** - * Remove one cgroup from specific controller. The function moves all - * processes from it to given target group. - * - * The function succeeds if the group to remove is already removed - when - * cgroup_delete_cgroup is called with group with two controllers mounted - * to the same hierarchy, this function is called once for each of these - * controllers. And during the second call the group is already removed... - * - * @param cgroup_name Name of the group to remove. - * @param controller Name of the controller. - * @param target_tasks Opened tasks file of the target group, where all - * processes should be moved. - * @param flags Flag indicating whether the errors from task - * migration should be ignored (CGROUP_DELETE_IGNORE_MIGRATION) or not (0). - * @returns 0 on success, >0 on error. - */ -static int cg_delete_cgroup_controller(char *cgroup_name, char *controller, - FILE *target_tasks, int flags) -{ - FILE *delete_tasks; - char path[FILENAME_MAX]; - int ret = 0; - - cgroup_dbg("Removing group %s:%s\n", controller, cgroup_name); - - if (!(flags & CGFLAG_DELETE_EMPTY_ONLY)) { - /* - * Open tasks file of the group to delete. - */ - if (!cg_build_path(cgroup_name, path, controller)) - return ECGROUPSUBSYSNOTMOUNTED; - strncat(path, "tasks", sizeof(path) - strlen(path)); - - delete_tasks = fopen(path, "re"); - if (delete_tasks) { - ret = cg_move_task_files(delete_tasks, target_tasks); - if (ret != 0) - cgroup_warn("Warning: removing tasks from %s failed: %s\n", - path, cgroup_strerror(ret)); - fclose(delete_tasks); - } else { - /* - * Can't open the tasks file. If the file does not - * exist, ignore it - the group has been already - * removed. - */ - if (errno != ENOENT) { - cgroup_err("Error: cannot open %s: %s\n", - path, strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - } - } - - if (ret != 0 && !(flags & CGFLAG_DELETE_IGNORE_MIGRATION)) - return ret; - } - - /* - * Remove the group. - */ - if (!cg_build_path(cgroup_name, path, controller)) - return ECGROUPSUBSYSNOTMOUNTED; - - ret = rmdir(path); - if (ret == 0 || errno == ENOENT) - return 0; - - if ((flags & CGFLAG_DELETE_EMPTY_ONLY) && (errno == EBUSY)) - return ECGNONEMPTY; - - cgroup_warn("Warning: cannot remove directory %s: %s\n", - path, strerror(errno)); - last_errno = errno; - return ECGOTHER; -} - -/** - * Recursively delete one control group. Moves all tasks from the group and - * its subgroups to given task file. - * - * @param cgroup_name The group to delete. - * @param controller The controller, where to delete. - * @param target_tasks Opened file, where all tasks should be moved. - * @param flags Combination of CGFLAG_DELETE_* flags. The function assumes - * that CGFLAG_DELETE_RECURSIVE is set. - * @param delete_root Whether the group itself should be removed(1) or not(0). - */ -static int cg_delete_cgroup_controller_recursive(char *cgroup_name, - char *controller, FILE *target_tasks, int flags, - int delete_root) -{ - int ret; - void *handle; - struct cgroup_file_info info; - int level, group_len; - char child_name[FILENAME_MAX + 1]; - - cgroup_dbg("Recursively removing %s:%s\n", controller, cgroup_name); - - ret = cgroup_walk_tree_begin(controller, cgroup_name, 0, &handle, - &info, &level); - - if (ret == 0) - ret = cgroup_walk_tree_set_flags(&handle, - CGROUP_WALK_TYPE_POST_DIR); - - if (ret != 0) { - cgroup_walk_tree_end(&handle); - return ret; - } - - group_len = strlen(info.full_path); - - /* - * Skip the root group, it will be handled explicitly at the end. - */ - ret = cgroup_walk_tree_next(0, &handle, &info, level); - - while (ret == 0) { - if (info.type == CGROUP_FILE_TYPE_DIR && info.depth > 0) { - snprintf(child_name, sizeof(child_name), "%s/%s", - cgroup_name, - info.full_path + group_len); - - ret = cg_delete_cgroup_controller(child_name, - controller, target_tasks, - flags); - if (ret != 0) - break; - } - - ret = cgroup_walk_tree_next(0, &handle, &info, level); - } - if (ret == ECGEOF) { - /* - * Iteration finished successfully, remove the root group. - */ - ret = 0; - if (delete_root) - ret = cg_delete_cgroup_controller(cgroup_name, - controller, target_tasks, - flags); - } - - cgroup_walk_tree_end(&handle); - return ret; -} - -/** cgroup_delete cgroup deletes a control group. - * struct cgroup *cgroup takes the group which is to be deleted. - * - * returns 0 on success. - */ -int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration) -{ - int flags = ignore_migration ? CGFLAG_DELETE_IGNORE_MIGRATION : 0; - return cgroup_delete_cgroup_ext(cgroup, flags); -} - -int cgroup_delete_cgroup_ext(struct cgroup *cgroup, int flags) -{ - FILE *parent_tasks = NULL; - char parent_path[FILENAME_MAX]; - int first_error = 0, first_errno = 0; - int i, ret; - char *parent_name = NULL; - int delete_group = 1; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!cgroup) - return ECGROUPNOTALLOWED; - - if ((flags & CGFLAG_DELETE_RECURSIVE) - && (flags & CGFLAG_DELETE_EMPTY_ONLY)) - return ECGINVAL; - - for (i = 0; i < cgroup->index; i++) { - if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) - return ECGROUPSUBSYSNOTMOUNTED; - } - - /* - * Remove the group from all controllers. - */ - for (i = 0; i < cgroup->index; i++) { - ret = 0; - - /* find parent, it can be different for each controller */ - if (!(flags & CGFLAG_DELETE_EMPTY_ONLY)) { - ret = cgroup_find_parent(cgroup, - cgroup->controller[i]->name, - &parent_name); - if (ret) { - if (first_error == 0) { - first_errno = last_errno; - first_error = ret; - } - continue; - } - if (parent_name == NULL) { - /* - * Root group is being deleted. - */ - if (flags & CGFLAG_DELETE_RECURSIVE) { - /* - * Move all tasks to the root group and - * do not delete it afterwards. - */ - parent_name = strdup("."); - if (parent_name == NULL) { - if (first_error == 0) { - first_errno = errno; - first_error = ECGOTHER; - } - continue; - } - delete_group = 0; - } else - /* - * root group is being deleted in non- - * recursive mode - */ - continue; - } - } - - if (parent_name) { - /* tasks need to be moved, pre-open target tasks file */ - if (!cg_build_path(parent_name, parent_path, - cgroup->controller[i]->name)) { - if (first_error == 0) - first_error = ECGFAIL; - free(parent_name); - continue; - } - strncat(parent_path, "/tasks", sizeof(parent_path) - - strlen(parent_path)); - - parent_tasks = fopen(parent_path, "we"); - if (!parent_tasks) { - if (first_error == 0) { - cgroup_warn("Warning: cannot open tasks file %s: %s\n", - parent_path, - strerror(errno)); - first_errno = errno; - first_error = ECGOTHER; - } - free(parent_name); - continue; - } - } - if (flags & CGFLAG_DELETE_RECURSIVE) { - ret = cg_delete_cgroup_controller_recursive( - cgroup->name, - cgroup->controller[i]->name, - parent_tasks, flags, - delete_group); - } else { - ret = cg_delete_cgroup_controller(cgroup->name, - cgroup->controller[i]->name, - parent_tasks, flags); - } - - if (parent_tasks) { - fclose(parent_tasks); - parent_tasks = NULL; - } - free(parent_name); - parent_name = NULL; - /* - * If any of the controller delete fails, remember the first - * error code, but continue with next controller and try remove - * the group from all of them. - */ - if (ret != 0 && first_error == 0) { - /* - * ECGNONEMPTY is more or less not an error, but an - * indication that something was not removed. - * Therefore it should be replaced by any other error. - */ - if (ret != ECGNONEMPTY || first_error == ECGNONEMPTY) { - first_errno = last_errno; - first_error = ret; - } - } - } - - /* - * Restore the last_errno to the first errno from - * cg_delete_cgroup_controller[_ext]. - */ - if (first_errno != 0) - last_errno = first_errno; - - return first_error; -} - -/* - * This function should really have more checks, but this version - * will assume that the callers have taken care of everything. - * Including the locking. - */ -static int cg_rd_ctrl_file(const char *subsys, const char *cgroup, - const char *file, char **value) -{ - char path[FILENAME_MAX]; - FILE *ctrl_file = NULL; - int ret; - - if (!cg_build_path_locked(cgroup, path, subsys)) - return ECGFAIL; - - strncat(path, file, sizeof(path) - strlen(path)); - ctrl_file = fopen(path, "re"); - if (!ctrl_file) - return ECGROUPVALUENOTEXIST; - - *value = calloc(CG_CONTROL_VALUE_MAX, 1); - if (!*value) { - fclose(ctrl_file); - last_errno = errno; - return ECGOTHER; - } - - /* - * using %as crashes when we try to read from files like - * memory.stat - */ - ret = fread(*value, 1, CG_CONTROL_VALUE_MAX-1, ctrl_file); - if (ret < 0) { - free(*value); - *value = NULL; - } else { - /* remove trailing \n */ - if (ret > 0 && (*value)[ret-1] == '\n') - (*value)[ret-1] = '\0'; - } - - fclose(ctrl_file); - - return 0; -} - -/* - * Call this function with required locks taken. - */ -static int cgroup_fill_cgc(struct dirent *ctrl_dir, struct cgroup *cgroup, - struct cgroup_controller *cgc, int cg_index) -{ - char *ctrl_name = NULL; - char *ctrl_file = NULL; - char *ctrl_value = NULL; - char *d_name = NULL; - char *tmp_path = NULL; - int tmp_len = 0; - char path[FILENAME_MAX+1]; - char *buffer = NULL; - int error = 0; - struct stat stat_buffer; - - d_name = strdup(ctrl_dir->d_name); - - if (!strcmp(d_name, ".") || !strcmp(d_name, "..")) { - error = ECGINVAL; - goto fill_error; - } - - - /* - * This part really needs to be optimized out. Probably use - * some sort of a flag, but this is fine for now. - */ - - cg_build_path_locked(cgroup->name, path, cg_mount_table[cg_index].name); - strncat(path, d_name, sizeof(path) - strlen(path)); - - error = stat(path, &stat_buffer); - - if (error) { - error = ECGFAIL; - goto fill_error; - } - - /* - * We have already stored the tasks_uid & tasks_gid. - * This check is to avoid the overwriting of the values - * stored in control_uid & cotrol_gid. tasks file will - * have the uid and gid of the user who is capable of - * putting a task to this cgroup. control_uid and control_gid - * is meant for the users who are capable of managing the - * cgroup shares. - * - * The strstr() function will return the pointer to the - * beginning of the sub string "/tasks". - */ - tmp_len = strlen(path) - strlen("/tasks"); - - /* - * tmp_path would be pointing to the last six characters - */ - tmp_path = (char *)path + tmp_len; - - /* - * Checking to see, if this is actually a 'tasks' file - * We need to compare the last 6 bytes - */ - if (strcmp(tmp_path, "/tasks")){ - cgroup->control_uid = stat_buffer.st_uid; - cgroup->control_gid = stat_buffer.st_gid; - } - - ctrl_name = strtok_r(d_name, ".", &buffer); - - if (!ctrl_name) { - error = ECGFAIL; - goto fill_error; - } - - ctrl_file = strtok_r(NULL, ".", &buffer); - - if (!ctrl_file) { - error = ECGINVAL; - goto fill_error; - } - - if (strcmp(ctrl_name, cg_mount_table[cg_index].name) == 0) { - error = cg_rd_ctrl_file(cg_mount_table[cg_index].name, - cgroup->name, ctrl_dir->d_name, &ctrl_value); - if (error || !ctrl_value) - goto fill_error; - - if (cgroup_add_value_string(cgc, ctrl_dir->d_name, - ctrl_value)) { - error = ECGFAIL; - goto fill_error; - } - } -fill_error: - if (ctrl_value) - free(ctrl_value); - free(d_name); - return error; -} - -/* - * cgroup_get_cgroup reads the cgroup data from the filesystem. - * struct cgroup has the name of the group to be populated - * - * return 0 on success. - */ -int cgroup_get_cgroup(struct cgroup *cgroup) -{ - int i, j; - char path[FILENAME_MAX]; - DIR *dir = NULL; - struct dirent *ctrl_dir = NULL; - char *control_path = NULL; - int error; - int ret; - - if (!cgroup_initialized) { - /* ECGROUPNOTINITIALIZED */ - return ECGROUPNOTINITIALIZED; - } - - if (!cgroup) { - /* ECGROUPNOTALLOWED */ - return ECGROUPNOTALLOWED; - } - - pthread_rwlock_rdlock(&cg_mount_table_lock); - for (i = 0; i < CG_CONTROLLER_MAX && - cg_mount_table[i].name[0] != '\0'; i++) { - struct cgroup_controller *cgc; - struct stat stat_buffer; - int path_len; - - if (!cg_build_path_locked(NULL, path, - cg_mount_table[i].name)) - continue; - - path_len = strlen(path); - strncat(path, cgroup->name, FILENAME_MAX - path_len - 1); - - if (access(path, F_OK)) - continue; - - if (!cg_build_path_locked(cgroup->name, path, - cg_mount_table[i].name)) { - /* - * This fails when the cgroup does not exist - * for that controller. - */ - continue; - } - - /* - * Get the uid and gid information - */ - - ret = asprintf(&control_path, "%s/tasks", path); - - if (ret < 0) { - last_errno = errno; - error = ECGOTHER; - goto unlock_error; - } - - if (stat(control_path, &stat_buffer)) { - last_errno = errno; - free(control_path); - error = ECGOTHER; - goto unlock_error; - } - - cgroup->tasks_uid = stat_buffer.st_uid; - cgroup->tasks_gid = stat_buffer.st_gid; - - free(control_path); - - cgc = cgroup_add_controller(cgroup, - cg_mount_table[i].name); - if (!cgc) { - error = ECGINVAL; - goto unlock_error; - } - - dir = opendir(path); - if (!dir) { - last_errno = errno; - error = ECGOTHER; - goto unlock_error; - } - - while ((ctrl_dir = readdir(dir)) != NULL) { - /* - * Skip over non regular files - */ - if (ctrl_dir->d_type != DT_REG) - continue; - - error = cgroup_fill_cgc(ctrl_dir, cgroup, cgc, i); - for (j = 0; j < cgc->index; j++) - cgc->values[j]->dirty = false; - - if (error == ECGFAIL) { - closedir(dir); - goto unlock_error; - } - } - closedir(dir); - - if (! strcmp(cgc->name, "memory")) { - /* - * Make sure that memory.limit_in_bytes is placed before - * memory.memsw.limit_in_bytes in the list of values - */ - int memsw_limit = -1; - int mem_limit = -1; - - for (j = 0; j < cgc->index; j++) { - if (! strcmp(cgc->values[j]->name, - "memory.memsw.limit_in_bytes")) - memsw_limit = j; - else if (! strcmp(cgc->values[j]->name, - "memory.limit_in_bytes")) - mem_limit = j; - } - - if (memsw_limit >= 0 && memsw_limit < mem_limit) { - struct control_value *val = cgc->values[memsw_limit]; - cgc->values[memsw_limit] = cgc->values[mem_limit]; - cgc->values[mem_limit] = val; - } - } - } - - /* Check if the group really exists or not */ - if (!cgroup->index) { - error = ECGROUPNOTEXIST; - goto unlock_error; - } - - pthread_rwlock_unlock(&cg_mount_table_lock); - return 0; - -unlock_error: - pthread_rwlock_unlock(&cg_mount_table_lock); - /* - * XX: Need to figure out how to cleanup? Cleanup just the stuff - * we added, or the whole structure. - */ - cgroup_free_controllers(cgroup); - cgroup = NULL; - return error; -} - -/** cg_prepare_cgroup - * Process the selected rule. Prepare the cgroup structure which can be - * used to add the task to destination cgroup. - * - * - * returns 0 on success. - */ -static int cg_prepare_cgroup(struct cgroup *cgroup, pid_t pid, - const char *dest, - const char * const controllers[]) -{ - int ret = 0, i; - const char *controller = NULL; - struct cgroup_controller *cptr = NULL; - - /* Fill in cgroup details. */ - cgroup_dbg("Will move pid %d to cgroup '%s'\n", pid, dest); - - strncpy(cgroup->name, dest, FILENAME_MAX); - cgroup->name[FILENAME_MAX-1] = '\0'; - - /* Scan all the controllers */ - for (i = 0; i < CG_CONTROLLER_MAX; i++) { - int j = 0; - if (!controllers[i]) - return 0; - controller = controllers[i]; - - /* If first string is "*" that means all the mounted - * controllers. */ - if (strcmp(controller, "*") == 0) { - pthread_rwlock_rdlock(&cg_mount_table_lock); - for (j = 0; j < CG_CONTROLLER_MAX && - cg_mount_table[j].name[0] != '\0'; j++) { - cgroup_dbg("Adding controller %s\n", - cg_mount_table[j].name); - cptr = cgroup_add_controller(cgroup, - cg_mount_table[j].name); - if (!cptr) { - cgroup_warn("Warning: adding controller '%s' failed\n", - cg_mount_table[j].name); - pthread_rwlock_unlock(&cg_mount_table_lock); - cgroup_free_controllers(cgroup); - return ECGROUPNOTALLOWED; - } - } - pthread_rwlock_unlock(&cg_mount_table_lock); - return ret; - } - - /* it is individual controller names and not "*" */ - cgroup_dbg("Adding controller %s\n", controller); - cptr = cgroup_add_controller(cgroup, controller); - if (!cptr) { - cgroup_warn("Warning: adding controller '%s' failed\n", - controller); - cgroup_free_controllers(cgroup); - return ECGROUPNOTALLOWED; - } - } - - return ret; -} - -/** - * Determines if the rule is a wildcard rule and if so, compares the - * wildcard rule against the new process. If the new process matches - * the wildcard rule, then this function returns true. Otherwise it - * returns false. - * - * @param rule_procname The procname field of the rule - * @param procname The name of the new process - * @return True if the procname matches the rule. False otherwise - */ -STATIC bool cgroup_compare_wildcard_procname(const char * const rule_procname, - const char * const procname) -{ - size_t rule_strlen = strlen(rule_procname); - - if (rule_procname[rule_strlen - 1] != '*') - /* this rule does not end in a wildcard */ - return false; - - /* compare the two strings up to the asterisk */ - if (strncmp(rule_procname, procname, rule_strlen - 1) != 0) - /* the strings did not match */ - return false; - - /* all checks passed. the wildcarded process matched this rule */ - return true; -} - -static int cgroup_find_matching_destination(char *cgroup_list[], - const char * const rule_dest, - int *matching_index) -{ - size_t rule_strlen = strlen(rule_dest); - int ret = -ENODATA; - int i; - - for (i = 0; i < MAX_MNT_ELEMENTS; i++) { - if (cgroup_list[i] == NULL) - break; - - if (rule_dest[rule_strlen - 1] == '/') { - /* - * Avoid a weird corner case where given a rule dest - * like 'folder/', we _don't_ want to match 'folder1' - */ - if (strlen(cgroup_list[i]) >= rule_strlen && - cgroup_list[i][rule_strlen - 1] != '/') - continue; - - /* - * Strip off the '/' at the end of the rule, as the - * destination from the cgroup_list will not have a - * trailing '/' - */ - rule_strlen--; - } - - if (strncmp(rule_dest, cgroup_list[i], - rule_strlen) == 0) { - *matching_index = i; - ret = 0; - break; - } - - } - - return ret; -} - -static int cgroup_find_matching_controller(char * const *rule_controllers, - const char * const pid_controller, - int *matching_index) -{ - int ret = -ENODATA; - int i; - - for (i = 0; i < MAX_MNT_ELEMENTS; i++) { - if (rule_controllers[i] == NULL) - break; - - if (strlen(rule_controllers[i]) != strlen(pid_controller)) - continue; - - if (strncmp(pid_controller, rule_controllers[i], - strlen(pid_controller)) == 0) { - *matching_index = i; - ret = 0; - break; - } - - } - - return ret; -} - -/** - * Evaluates if rule is an ignore rule and the pid/procname match this rule. - * If rule is an ignore rule and the pid/procname match this rule, then this - * function returns true. Otherwise it returns false. - * - * @param rule Rule being evaluated - * @param pid PID of the process being compared - * @param procname Process name of the process being compared - * @return True if the rule is an ignore rule and this pid/procname - * match the rule. False otherwise - */ -STATIC bool cgroup_compare_ignore_rule(const struct cgroup_rule * const rule, - pid_t pid, const char * const procname) -{ - char *controller_list[MAX_MNT_ELEMENTS] = { '\0' }; - char *cgroup_list[MAX_MNT_ELEMENTS] = { '\0' }; - char *token, *saveptr; - bool found_match = false; - int rule_matching_controller_idx; - int cgroup_list_matching_idx; - int ret, i; - - if (!rule->is_ignore) - /* immediately return if the 'ignore' option is not set */ - return false; - - ret = cg_get_cgroups_from_proc_cgroups(pid, cgroup_list, - controller_list, - MAX_MNT_ELEMENTS); - if (ret < 0) - goto out; - - ret = cgroup_find_matching_destination(cgroup_list, rule->destination, - &cgroup_list_matching_idx); - if (ret < 0) - /* no cgroups matched */ - goto out; - - - token = strtok_r(controller_list[cgroup_list_matching_idx], - ",", &saveptr); - while (token != NULL) { - - ret = cgroup_find_matching_controller(rule->controllers, - token, &rule_matching_controller_idx); - if (ret == 0) - /* we found a matching controller */ - break; - - token = strtok_r(NULL, ",", &saveptr); - } - - if (!rule->procname) { - /* - * The rule procname is empty, thus it's a wildcard and all - * processes match. - */ - found_match = true; - goto out; - } - - if (!strcmp(rule->procname, procname)) { - found_match = true; - goto out; - } - - if (cgroup_compare_wildcard_procname(rule->procname, procname)) { - found_match = true; - } - -out: - for (i = 0; i < MAX_MNT_ELEMENTS; i++) { - if (controller_list[i]) - free(controller_list[i]); - if (cgroup_list[i]) - free(cgroup_list[i]); - } - - return found_match; -} - -static struct cgroup_rule *cgroup_find_matching_rule_uid_gid(uid_t uid, - gid_t gid, struct cgroup_rule *rule) -{ - /* Temporary user data */ - struct passwd *usr = NULL; - - /* Temporary group data */ - struct group *grp = NULL; - - /* Temporary string pointer */ - char *sp = NULL; - - /* Loop variable */ - int i = 0; - - while (rule) { - /* Skip "%" which indicates continuation of previous rule. */ - if (rule->username[0] == '%') { - rule = rule->next; - continue; - } - /* The wildcard rule always matches. */ - if ((rule->uid == CGRULE_WILD) && (rule->gid == CGRULE_WILD)) - return rule; - - /* This is the simple case of the UID matching. */ - if (rule->uid == uid) - return rule; - - /* This is the simple case of the GID matching. */ - if (rule->gid == gid) - return rule; - - /* If this is a group rule, the UID might be a member. */ - if (rule->username[0] == '@') { - /* Get the group data. */ - sp = &(rule->username[1]); - grp = getgrnam(sp); - if (!grp) { - rule = rule->next; - continue; - } - - /* Get the data for UID. */ - usr = getpwuid(uid); - if (!usr) { - rule = rule->next; - continue; - } - - /* If UID is a member of group, we matched. */ - for (i = 0; grp->gr_mem[i]; i++) { - if (!(strcmp(usr->pw_name, grp->gr_mem[i]))) - return rule; - } - } - - /* If we haven't matched, try the next rule. */ - rule = rule->next; - } - - /* If we get here, no rules matched. */ - return NULL; -} - -/** - * Finds the first rule in the cached list that matches the given UID, GID - * or PROCESS NAME, and returns a pointer to that rule. - * This function uses rl_lock. - * - * This function may NOT be thread safe. - * @param uid The UID to match - * @param gid The GID to match - * @param procname The PROCESS NAME to match - * @return Pointer to the first matching rule, or NULL if no match - * TODO: Determine thread-safeness and fix if not safe. - */ -static struct cgroup_rule *cgroup_find_matching_rule(uid_t uid, - gid_t gid, pid_t pid, const char *procname) -{ - /* Return value */ - struct cgroup_rule *ret = rl.head; - char *base = NULL; - - pthread_rwlock_wrlock(&rl_lock); - while (ret) { - ret = cgroup_find_matching_rule_uid_gid(uid, gid, ret); - if (!ret) - break; - if (cgroup_compare_ignore_rule(ret, pid, procname)) - /* - * This pid matched a rule that instructs the cgrules - * daemon to ignore this process. - */ - break; - if (ret->is_ignore) { - /* - * The rule currently being examined is an ignore - * rule, but it didn't match this pid. Move on to - * the next rule - */ - ret = ret->next; - continue; - } - if (!procname) - /* If procname is NULL, return a rule matching - * UID or GID */ - break; - if (!ret->procname) - /* If no process name in a rule, that means wildcard */ - break; - if (!strcmp(ret->procname, procname)) - break; - - base = cgroup_basename(procname); - if (!strcmp(ret->procname, base)) - /* Check a rule of basename. */ - break; - if (cgroup_compare_wildcard_procname(ret->procname, procname)) - break; - ret = ret->next; - free(base); - base = NULL; - } - pthread_rwlock_unlock(&rl_lock); - - if (base) - free(base); - - return ret; -} - -/* Procedure the existence of cgroup "prefix" is in subsystem controller_name - * return 0 on success - */ -int cgroup_exist_in_subsystem(char *controller_name, char *prefix) -{ - DIR *dir; - char path[FILENAME_MAX]; - char *ret_path; - int ret; - - pthread_rwlock_rdlock(&cg_mount_table_lock); - ret_path = cg_build_path_locked(prefix, path, controller_name); - pthread_rwlock_unlock(&cg_mount_table_lock); - if (!ret_path) { - ret = 1; - goto end; - } - - dir = opendir(path); - if (dir == NULL) { - /* cgroup in wanted subsystem does not exist */ - ret = 1; - } else { - /* cgroup in wanted subsystem exists */ - ret = 0; - closedir(dir); - } -end: - return ret; -} - -/* auxiliary function return a pointer to the string - * which is copy of input string and end with the slash - */ -char *cgroup_copy_with_slash(char *input) -{ - char *output; - int len = strlen(input); - - /* if input does not end with '/', allocate one more space for it */ - if ((input[len-1]) != '/') - len = len+1; - - output = (char *)malloc(sizeof(char)*(len+1)); - if (output == NULL) - return NULL; - - strcpy(output, input); - output[len-1] = '/'; - output[len] = '\0'; - - return output; -} - -/* add controller to a group if it is not exists create it */ -static int add_controller(struct cgroup **pgroup, char *group_name, - char controller_name[FILENAME_MAX]) -{ - int ret = 0; - struct cgroup_controller *controller = NULL; - struct cgroup *group = pgroup[0]; - - if (group == NULL) { - /* it is the first controllerc the group have to be created */ - group = cgroup_new_cgroup(group_name); - if (group == NULL) { - ret = ECGFAIL; - goto end; - } - pgroup[0] = group; - } - - controller = cgroup_add_controller( - group, controller_name); - if (controller == NULL) { - cgroup_free(&group); - ret = ECGFAIL; - } -end: - return ret; -} - - - -/* create control group based given template - * if the group already don't exist - * dest is template name with substitute variables - * tmp is used cgrules rule - */ -static int cgroup_create_template_group(char *orig_group_name, - struct cgroup_rule *tmp, int flags) -{ - - char *template_name = NULL; /* name of the template */ - char *group_name = NULL; /* name of the group based on template - - variables are substituted */ - char *template_position; /* denotes directory in template path - which is investigated */ - char *group_position; /* denotes directory in cgroup path - which is investigated */ - - struct cgroup *template_group = NULL; - int ret = 0; - int i; - int exist; - - /* template name and group name have to have '/' sign at the end */ - template_name = cgroup_copy_with_slash(tmp->destination); - if (template_name == NULL) { - ret = ECGOTHER; - last_errno = errno; - goto end; - } - group_name = cgroup_copy_with_slash(orig_group_name); - if (group_name == NULL) { - ret = ECGOTHER; - last_errno = errno; - free(template_name); - template_name = NULL; - goto end; - } - - /* set start positions */ - template_position = strchr(template_name, '/'); - group_position = strchr(group_name, '/'); - - /* go recursively through whole path to template group and create given - * directory if it does not exist yet - */ - while ((group_position != NULL) && (template_position != NULL)) { - /* set new subpath */ - group_position[0] = '\0'; - template_position[0] = '\0'; - template_group = NULL; - - /* test for which controllers wanted group does not exist */ - i = 0; - while (tmp->controllers[i] != NULL) { - exist = cgroup_exist_in_subsystem(tmp->controllers[i], - group_name); - - if (exist != 0) { - /* the cgroup does not exist */ - ret = add_controller(&template_group, group_name, - tmp->controllers[i]); - if (ret != 0) - goto while_end; - } - i++; - } - - if (template_group != NULL) { - /* new group have to be created */ - if (strcmp(group_name, template_name) == 0) { - /* the prefix cgroup without template */ - ret = cgroup_create_cgroup(template_group, 0); - } else { - /* use template to create relevant cgroup */ - ret = cgroup_config_create_template_group( - template_group, template_name, - flags); - } - - if (ret != 0) { - cgroup_free(&template_group); - goto while_end; - } - cgroup_dbg("Group %s created - based on template %s\n", - group_name, template_name); - - cgroup_free(&template_group); - } - template_position[0] = '/'; - group_position[0] = '/'; - template_position = strchr(++template_position, '/'); - group_position = strchr(++group_position, '/'); - } - -while_end: - if ((template_position != NULL ) && (template_position[0] == '\0')) - template_position[0] = '/'; - if ((group_position != NULL) && (group_position[0] == '\0')) - group_position[0] = '/'; - -end: - if (group_name != NULL) - free(group_name); - if (template_name != NULL) - free(template_name); - return ret; -} - -int cgroup_change_cgroup_flags(uid_t uid, gid_t gid, - const char *procname, pid_t pid, int flags) -{ - /* Temporary pointer to a rule */ - struct cgroup_rule *tmp = NULL; - - /* Temporary variables for destination substitution */ - char newdest[FILENAME_MAX]; - int i, j; - int written; - int available; - struct passwd *user_info; - struct group *group_info; - - /* Return codes */ - int ret = 0; - - /* We need to check this before doing anything else! */ - if (!cgroup_initialized) { - cgroup_warn("Warning: libcgroup is not initialized\n"); - ret = ECGROUPNOTINITIALIZED; - goto finished; - } - - /* - * If the user did not ask for cached rules, we must parse the - * configuration to find a matching rule (if one exists). Else, we'll - * find the first match in the cached list (rl). - */ - if (!(flags & CGFLAG_USECACHE)) { - cgroup_dbg("Not using cached rules for PID %d.\n", pid); - ret = cgroup_parse_rules(false, uid, gid, procname); - - /* The configuration file has an error! We must exit now. */ - if (ret != -1 && ret != 0) { - cgroup_err("Error: failed to parse the configuration rules\n"); - goto finished; - } - - /* We did not find a matching rule, so we're done. */ - if (ret == 0) { - cgroup_dbg("No rule found to match PID: %d, UID: %d, " - "GID: %d\n", pid, uid, gid); - goto finished; - } - - /* Otherwise, we did match a rule and it's in trl. */ - tmp = trl.head; - } else { - /* Find the first matching rule in the cached list. */ - tmp = cgroup_find_matching_rule(uid, gid, pid, procname); - if (!tmp) { - cgroup_dbg("No rule found to match PID: %d, UID: %d, " - "GID: %d\n", pid, uid, gid); - ret = 0; - goto finished; - } - } - cgroup_dbg("Found matching rule %s for PID: %d, UID: %d, GID: %d\n", - tmp->username, pid, uid, gid); - - if (tmp->is_ignore) { - /* - * This rule has instructed us that this pid is not to be - * processed and should be ignored - */ - cgroup_dbg("Matching rule is an ignore rule\n"); - ret = 0; - goto finished; - } - - /* If we are here, then we found a matching rule, so execute it. */ - do { - cgroup_dbg("Executing rule %s for PID %d... ", tmp->username, - pid); - /* Destination substitutions */ - for(j = i = 0; i < strlen(tmp->destination) && - (j < FILENAME_MAX - 2); ++i, ++j) { - if(tmp->destination[i] == '%') { - /* How many bytes did we write / error check */ - written = 0; - /* How many bytes can we write */ - available = FILENAME_MAX - j - 2; - /* Substitution */ - switch(tmp->destination[++i]) { - case 'U': - written = snprintf(newdest+j, available, - "%d", uid); - break; - case 'u': - user_info = getpwuid(uid); - if(user_info) { - written = snprintf(newdest + j, - available, "%s", - user_info -> pw_name); - } else { - written = snprintf(newdest + j, - available, "%d", uid); - } - break; - case 'G': - written = snprintf(newdest + j, - available, "%d", gid); - break; - case 'g': - group_info = getgrgid(gid); - if(group_info) { - written = snprintf(newdest + j, - available, "%s", - group_info -> gr_name); - } else { - written = snprintf(newdest + j, - available, "%d", gid); - } - break; - case 'P': - written = snprintf(newdest + j, - available, "%d", pid); - break; - case 'p': - if(procname) { - written = snprintf(newdest + j, - available, "%s", - procname); - } else { - written = snprintf(newdest + j, - available, "%d", pid); - } - break; - } - written = min(written, available); - /* - * written<1 only when either error occurred - * during snprintf or if no substitution was - * made at all. In both cases, we want to just - * copy input string. - */ - if(written<1) { - newdest[j] = '%'; - if(available>1) - newdest[++j] = - tmp->destination[i]; - } else { - /* - * In next iteration, we will write - * just after the substitution, but j - * will get incremented in the - * meantime. - */ - j += written - 1; - } - } else { - if(tmp->destination[i] == '\\') - ++i; - newdest[j] = tmp->destination[i]; - } - } - - newdest[j] = 0; - if (strcmp(newdest, tmp->destination) != 0) { - /* destination tag contains templates */ - - cgroup_dbg("control group %s is template\n", newdest); - ret = cgroup_create_template_group(newdest, tmp, flags); - } - - /* Apply the rule */ - ret = cgroup_change_cgroup_path(newdest, - pid, (const char * const *)tmp->controllers); - if (ret) { - cgroup_warn("Warning: failed to apply the rule. Error was: %d\n", - ret); - goto finished; - } - cgroup_dbg("OK!\n"); - - /* Now, check for multi-line rules. As long as the "next" - * rule starts with '%', it's actually part of the rule that - * we just executed. - */ - tmp = tmp->next; - } while (tmp && (tmp->username[0] == '%')); - -finished: - return ret; -} - -int cgroup_change_cgroup_uid_gid_flags(uid_t uid, gid_t gid, - pid_t pid, int flags) -{ - return cgroup_change_cgroup_flags(uid, gid, NULL, pid, flags); -} - -/** - * Provides backwards-compatibility with older versions of the API. This - * function is deprecated, and cgroup_change_cgroup_uid_gid_flags() should be - * used instead. In fact, this function simply calls the newer one with flags - * set to 0 (none). - * @param uid The UID to match - * @param gid The GID to match - * @param pid The PID of the process to move - * @return 0 on success, > 0 on error - * - */ -int cgroup_change_cgroup_uid_gid(uid_t uid, gid_t gid, pid_t pid) -{ - return cgroup_change_cgroup_uid_gid_flags(uid, gid, pid, 0); -} - -/** - * Changes the cgroup of a program based on the path provided. In this case, - * the user must already know into which cgroup the task should be placed and - * no rules will be parsed. - * - * returns 0 on success. - */ -int cgroup_change_cgroup_path(const char *dest, pid_t pid, - const char *const controllers[]) -{ - int ret; - int nr; - struct cgroup cgroup; - DIR *dir; - struct dirent *task_dir = NULL; - char path[FILENAME_MAX]; - pid_t tid; - - if (!cgroup_initialized) { - cgroup_warn("Warning: libcgroup is not initialized\n"); - return ECGROUPNOTINITIALIZED; - } - memset(&cgroup, 0, sizeof(struct cgroup)); - - ret = cg_prepare_cgroup(&cgroup, pid, dest, controllers); - if (ret) - return ret; - /* Add process to cgroup */ - ret = cgroup_attach_task_pid(&cgroup, pid); - if (ret) { - cgroup_warn("Warning: cgroup_attach_task_pid failed: %d\n", - ret); - goto finished; - } - - /* Add all threads to cgroup */ - snprintf(path, FILENAME_MAX, "/proc/%d/task/", pid); - dir = opendir(path); - if (!dir) { - last_errno = errno; - ret = ECGOTHER; - goto finished; - } - - while ((task_dir = readdir(dir)) != NULL) { - nr = sscanf(task_dir->d_name, "%i", &tid); - if (nr < 1) - continue; - - if (tid == pid) - continue; - - ret = cgroup_attach_task_pid(&cgroup, tid); - if (ret) { - cgroup_warn("Warning: cgroup_attach_task_pid failed: %d\n", - ret); - break; - } - } - - closedir(dir); - -finished: - cgroup_free_controllers(&cgroup); - return ret; -} - -/** - * Changes the cgroup of all running PIDs based on the rules in the config - * file. If a rules exists for a PID, then the PID is placed in the correct - * group. - * - * This function may be called after creating new control groups to move - * running PIDs into the newly created control groups. - * @return 0 on success, < 0 on error - */ -int cgroup_change_all_cgroups(void) -{ - DIR *dir; - struct dirent *pid_dir = NULL; - char *path = "/proc/"; - - dir = opendir(path); - if (!dir) - return -ECGOTHER; - - while ((pid_dir = readdir(dir)) != NULL) { - int err, pid; - uid_t euid; - gid_t egid; - char *procname = NULL; - - err = sscanf(pid_dir->d_name, "%i", &pid); - if (err < 1) - continue; - - err = cgroup_get_uid_gid_from_procfs(pid, &euid, &egid); - if (err) - continue; - - err = cgroup_get_procname_from_procfs(pid, &procname); - if (err) - continue; - - err = cgroup_change_cgroup_flags(euid, - egid, procname, pid, CGFLAG_USECACHE); - if (err) - cgroup_dbg("cgroup change pid %i failed\n", pid); - - free(procname); - } - - closedir(dir); - return 0; -} - -/** - * Print the cached rules table. This function should be called only after - * first calling cgroup_parse_config(), but it will work with an empty rule - * list. - * @param fp The file stream to print to - */ -void cgroup_print_rules_config(FILE *fp) -{ - /* Iterator */ - struct cgroup_rule *itr = NULL; - - /* Loop variable */ - int i = 0; - - pthread_rwlock_rdlock(&rl_lock); - - if (!(rl.head)) { - fprintf(fp, "The rules table is empty.\n\n"); - pthread_rwlock_unlock(&rl_lock); - return; - } - - itr = rl.head; - while (itr) { - fprintf(fp, "Rule: %s", itr->username); - if (itr->procname) - fprintf(fp, ":%s", itr->procname); - fprintf(fp, "\n"); - - if (itr->uid == CGRULE_WILD) - fprintf(fp, " UID: any\n"); - else if (itr->uid == CGRULE_INVALID) - fprintf(fp, " UID: N/A\n"); - else - fprintf(fp, " UID: %d\n", itr->uid); - - if (itr->gid == CGRULE_WILD) - fprintf(fp, " GID: any\n"); - else if (itr->gid == CGRULE_INVALID) - fprintf(fp, " GID: N/A\n"); - else - fprintf(fp, " GID: %d\n", itr->gid); - - fprintf(fp, " DEST: %s\n", itr->destination); - - fprintf(fp, " CONTROLLERS:\n"); - for (i = 0; i < MAX_MNT_ELEMENTS; i++) { - if (itr->controllers[i]) - fprintf(fp, " %s\n", itr->controllers[i]); - } - fprintf(fp, " OPTIONS:\n"); - if (itr->is_ignore) - fprintf(fp, " IS_IGNORE: True\n"); - else - fprintf(fp, " IS_IGNORE: False\n"); - fprintf(fp, "\n"); - itr = itr->next; - } - pthread_rwlock_unlock(&rl_lock); -} - -/** - * Reloads the rules list, using the given configuration file. This function - * is probably NOT thread safe (calls cgroup_parse_rules()). - * @return 0 on success, > 0 on failure - */ -int cgroup_reload_cached_rules(void) -{ - /* Return codes */ - int ret = 0; - - cgroup_dbg("Reloading cached rules from %s.\n", CGRULES_CONF_FILE); - ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL); - if (ret) { - cgroup_warn("Warning: error parsing configuration file '%s': %d\n", - CGRULES_CONF_FILE, ret); - ret = ECGRULESPARSEFAIL; - goto finished; - } - - #ifdef CGROUP_DEBUG - cgroup_print_rules_config(stdout); - #endif - -finished: - return ret; -} - -/** - * Initializes the rules cache. - * @return 0 on success, > 0 on error - */ -int cgroup_init_rules_cache(void) -{ - /* Return codes */ - int ret = 0; - - /* Attempt to read the configuration file and cache the rules. */ - ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL); - if (ret) { - cgroup_dbg("Could not initialize rule cache, error was: %d\n", - ret); - } - - return ret; -} - -/** - * cgroup_get_current_controller_path - * @pid: pid of the current process for which the path is to be determined - * @controller: name of the controller for which to determine current path - * @current_path: a pointer that is filled with the value of the current - * path as seen in /proc//cgroup - */ -int cgroup_get_current_controller_path(pid_t pid, const char *controller, - char **current_path) -{ - char *path = NULL; - int ret; - FILE *pid_cgroup_fd = NULL; - - if (!controller) - return ECGOTHER; - - if (!cgroup_initialized) { - cgroup_warn("Warning: libcgroup is not initialized\n"); - return ECGROUPNOTINITIALIZED; - } - - ret = asprintf(&path, "/proc/%d/cgroup", pid); - if (ret <= 0) { - cgroup_warn( - "Warning: cannot allocate memory (/proc/pid/cgroup) ret %d\n", - ret); - return ret; - } - - ret = ECGROUPNOTEXIST; - pid_cgroup_fd = fopen(path, "re"); - if (!pid_cgroup_fd) - goto cleanup_path; - - /* - * Why do we grab the cg_mount_table_lock?, the reason is that - * the cgroup of a pid can change via the cgroup_attach_task_pid() - * call. To make sure, we return consitent and safe results, - * we acquire the lock upfront. We can optimize by acquiring - * and releasing the lock in the while loop, but that - * will be more expensive. - */ - pthread_rwlock_rdlock(&cg_mount_table_lock); - while (!feof(pid_cgroup_fd)) { - char controllers[FILENAME_MAX]; - char cgroup_path[FILENAME_MAX]; - int num; - char *savedptr; - char *token; - - ret = fscanf(pid_cgroup_fd, "%d:%[^:]:%s\n", &num, controllers, - cgroup_path); - /* - * Magic numbers like "3" seem to be integrating into - * my daily life, I need some magic to help make them - * disappear :) - */ - if (ret != 3) { - cgroup_warn("Warning: read failed for pid_cgroup_fd ret %d\n", - ret); - last_errno = errno; - ret = ECGOTHER; - goto done; - } - - token = strtok_r(controllers, ",", &savedptr); - while (token) { - if (strncmp(controller, token, strlen(controller) + 1) - == 0) { - *current_path = strdup(cgroup_path); - if (!*current_path) { - last_errno = errno; - ret = ECGOTHER; - goto done; - } - ret = 0; - goto done; - } - token = strtok_r(NULL, ",", &savedptr); - } - } - -done: - pthread_rwlock_unlock(&cg_mount_table_lock); - fclose(pid_cgroup_fd); -cleanup_path: - free(path); - return ret; -} - -const char *cgroup_strerror(int code) -{ - if (code == ECGOTHER) - return strerror_r(cgroup_get_last_errno(), errtext, MAXLEN); - - return cgroup_strerror_codes[code % ECGROUPNOTCOMPILED]; -} - -/** - * Return last errno, which caused ECGOTHER error. - */ -int cgroup_get_last_errno(void) -{ - return last_errno; -} - - -static int cg_walk_node(FTS *fts, FTSENT *ent, const int depth, - struct cgroup_file_info *info, int dir) -{ - int ret = 0; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - cgroup_dbg("seeing file %s\n", ent->fts_path); - - info->path = ent->fts_name; - info->parent = ent->fts_parent->fts_name; - info->full_path = ent->fts_path; - info->depth = ent->fts_level; - info->type = CGROUP_FILE_TYPE_OTHER; - - if (depth && (info->depth > depth)) - return 0; - - switch (ent->fts_info) { - case FTS_DNR: - case FTS_ERR: - errno = ent->fts_errno; - break; - case FTS_D: - if (dir & CGROUP_WALK_TYPE_PRE_DIR) - info->type = CGROUP_FILE_TYPE_DIR; - break; - case FTS_DC: - case FTS_NSOK: - case FTS_NS: - case FTS_DP: - if (dir & CGROUP_WALK_TYPE_POST_DIR) - info->type = CGROUP_FILE_TYPE_DIR; - break; - case FTS_F: - info->type = CGROUP_FILE_TYPE_FILE; - break; - case FTS_DEFAULT: - break; - } - return ret; -} - -int cgroup_walk_tree_next(int depth, void **handle, - struct cgroup_file_info *info, int base_level) -{ - int ret = 0; - struct cgroup_tree_handle *entry; - FTSENT *ent; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - entry = (struct cgroup_tree_handle *) *handle; - - ent = fts_read(entry->fts); - if (!ent) - return ECGEOF; - if (!base_level && depth) - base_level = ent->fts_level + depth; - - ret = cg_walk_node(entry->fts, ent, base_level, info, entry->flags); - - *handle = entry; - return ret; -} - -int cgroup_walk_tree_end(void **handle) -{ - struct cgroup_tree_handle *entry; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - entry = (struct cgroup_tree_handle *) *handle; - - fts_close(entry->fts); - free(entry); - *handle = NULL; - return 0; -} - -/* - * TODO: Need to decide a better place to put this function. - */ -int cgroup_walk_tree_begin(const char *controller, const char *base_path, - int depth, void **handle, struct cgroup_file_info *info, - int *base_level) -{ - int ret = 0; - char *cg_path[2]; - char full_path[FILENAME_MAX]; - FTSENT *ent; - struct cgroup_tree_handle *entry; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - cgroup_dbg("path is %s\n", base_path); - - if (!cg_build_path(base_path, full_path, controller)) - return ECGOTHER; - - entry = calloc(sizeof(struct cgroup_tree_handle), 1); - - if (!entry) { - last_errno = errno; - *handle = NULL; - return ECGOTHER; - } - - entry->flags |= CGROUP_WALK_TYPE_PRE_DIR; - - *base_level = 0; - cg_path[0] = full_path; - cg_path[1] = NULL; - - entry->fts = fts_open(cg_path, FTS_LOGICAL | FTS_NOCHDIR | - FTS_NOSTAT, NULL); - if (entry->fts == NULL) { - free(entry); - last_errno = errno; - *handle = NULL; - return ECGOTHER; - } - ent = fts_read(entry->fts); - if (!ent) { - cgroup_warn("Warning: fts_read failed\n"); - fts_close(entry->fts); - free(entry); - *handle = NULL; - return ECGINVAL; - } - if (!*base_level && depth) - *base_level = ent->fts_level + depth; - - ret = cg_walk_node(entry->fts, ent, *base_level, info, entry->flags); - if (ret != 0) { - fts_close(entry->fts); - free(entry); - *handle = NULL; - } else { - *handle = entry; - } - return ret; -} - -int cgroup_walk_tree_set_flags(void **handle, int flags) -{ - struct cgroup_tree_handle *entry; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - if ((flags & CGROUP_WALK_TYPE_PRE_DIR) && - (flags & CGROUP_WALK_TYPE_POST_DIR)) - return ECGINVAL; - - entry = (struct cgroup_tree_handle *) *handle; - entry->flags = flags; - - *handle = entry; - return 0; -} - -/* - * This parses a stat line which is in the form of (name value) pair - * separated by a space. - */ -static int cg_read_stat(FILE *fp, struct cgroup_stat *cgroup_stat) -{ - int ret = 0; - char *line = NULL; - size_t len = 0; - ssize_t read_bytes; - char *token; - char *saveptr = NULL; - - read_bytes = getline(&line, &len, fp); - if (read_bytes == -1) { - ret = ECGEOF; - goto out_free; - } - - token = strtok_r(line, " ", &saveptr); - if (!token) { - ret = ECGINVAL; - goto out_free; - } - strncpy(cgroup_stat->name, token, FILENAME_MAX - 1); - - token = strtok_r(NULL, " ", &saveptr); - if (!token) { - ret = ECGINVAL; - goto out_free; - } - strncpy(cgroup_stat->value, token, CG_VALUE_MAX - 1); - -out_free: - free(line); - return ret; -} - - -int cgroup_read_value_end(void **handle) -{ - FILE *fp; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - fp = (FILE *)*handle; - fclose(fp); - - return 0; -} - -int cgroup_read_value_next(void **handle, char *buffer, int max) -{ - int ret = 0; - char *ret_c; - FILE *fp; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!buffer || !handle) - return ECGINVAL; - - fp = (FILE *)*handle; - ret_c = fgets(buffer, max, fp); - if (ret_c == NULL) - ret = ECGEOF; - - return ret; -} - -int cgroup_read_value_begin(const char *controller, const char *path, - char *name, void **handle, char *buffer, int max) -{ - int ret = 0; - char *ret_c = NULL; - char stat_file[FILENAME_MAX + sizeof(name)]; - char stat_path[FILENAME_MAX]; - FILE *fp; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!buffer || !handle) - return ECGINVAL; - - if (!cg_build_path(path, stat_path, controller)) - return ECGOTHER; - - snprintf(stat_file, sizeof(stat_file), "%s/%s", stat_path, - name); - fp = fopen(stat_file, "re"); - if (!fp) { - cgroup_warn("Warning: fopen failed\n"); - last_errno = errno; - *handle = NULL; - return ECGOTHER; - } - - ret_c = fgets(buffer, max, fp); - if (ret_c == NULL) - ret = ECGEOF; - - *handle = fp; - return ret; -} - - - -int cgroup_read_stats_end(void **handle) -{ - FILE *fp; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - fp = (FILE *)*handle; - if (fp == NULL) - return ECGINVAL; - - fclose(fp); - return 0; -} - -int cgroup_read_stats_next(void **handle, struct cgroup_stat *cgroup_stat) -{ - int ret = 0; - FILE *fp; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle || !cgroup_stat) - return ECGINVAL; - - fp = (FILE *)*handle; - ret = cg_read_stat(fp, cgroup_stat); - *handle = fp; - return ret; -} - -/* - * TODO: Need to decide a better place to put this function. - */ -int cgroup_read_stats_begin(const char *controller, const char *path, - void **handle, struct cgroup_stat *cgroup_stat) -{ - int ret = 0; - char stat_file[FILENAME_MAX + sizeof(".stat")]; - char stat_path[FILENAME_MAX]; - FILE *fp; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!cgroup_stat || !handle) - return ECGINVAL; - - if (!cg_build_path(path, stat_path, controller)) - return ECGOTHER; - - snprintf(stat_file, sizeof(stat_file), "%s/%s.stat", stat_path, - controller); - - fp = fopen(stat_file, "re"); - if (!fp) { - cgroup_warn("Warning: fopen failed\n"); - return ECGINVAL; - } - - ret = cg_read_stat(fp, cgroup_stat); - *handle = fp; - return ret; -} - -int cgroup_get_task_end(void **handle) -{ - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!*handle) - return ECGINVAL; - - fclose((FILE *) *handle); - *handle = NULL; - - return 0; -} - -int cgroup_get_task_next(void **handle, pid_t *pid) -{ - int ret; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!handle) - return ECGINVAL; - - ret = fscanf((FILE *) *handle, "%u", pid); - - if (ret != 1) { - if (ret == EOF) - return ECGEOF; - last_errno = errno; - return ECGOTHER; - } - - return 0; -} - -int cgroup_get_task_begin(const char *cgroup, const char *controller, - void **handle, pid_t *pid) -{ - int ret = 0; - char path[FILENAME_MAX]; - char *fullpath = NULL; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!cg_build_path(cgroup, path, controller)) - return ECGOTHER; - - ret = asprintf(&fullpath, "%s/tasks", path); - - if (ret < 0) { - last_errno = errno; - return ECGOTHER; - } - - *handle = (void *) fopen(fullpath, "re"); - free(fullpath); - - if (!*handle) { - last_errno = errno; - return ECGOTHER; - } - ret = cgroup_get_task_next(handle, pid); - - return ret; -} - - -int cgroup_get_controller_end(void **handle) -{ - int *pos = (int *) *handle; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!pos) - return ECGINVAL; - - free(pos); - *handle = NULL; - - return 0; -} - -int cgroup_get_controller_next(void **handle, struct cgroup_mount_point *info) -{ - int *pos = (int *) *handle; - int ret = 0; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!pos) - return ECGINVAL; - - if (!info) - return ECGINVAL; - - pthread_rwlock_rdlock(&cg_mount_table_lock); - - if (cg_mount_table[*pos].name[0] == '\0') { - ret = ECGEOF; - goto out_unlock; - } - - strncpy(info->name, cg_mount_table[*pos].name, FILENAME_MAX - 1); - - strncpy(info->path, cg_mount_table[*pos].mount.path, FILENAME_MAX - 1); - - (*pos)++; - *handle = pos; - -out_unlock: - pthread_rwlock_unlock(&cg_mount_table_lock); - return ret; -} - -int cgroup_get_controller_begin(void **handle, struct cgroup_mount_point *info) -{ - int *pos; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!info) - return ECGINVAL; - - pos = malloc(sizeof(int)); - - if (!pos) { - last_errno = errno; - return ECGOTHER; - } - - *pos = 0; - - *handle = pos; - - return cgroup_get_controller_next(handle, info); -} - -/** - * Get process data (euid and egid) from /proc//status file. - * @param pid: The process id - * @param euid: The uid of param pid - * @param egid: The gid of param pid - * @return 0 on success, > 0 on error. - */ -int cgroup_get_uid_gid_from_procfs(pid_t pid, uid_t *euid, gid_t *egid) -{ - FILE *f; - char path[FILENAME_MAX]; - char buf[4092]; - uid_t ruid, suid, fsuid; - gid_t rgid, sgid, fsgid; - bool found_euid = false; - bool found_egid = false; - - sprintf(path, "/proc/%d/status", pid); - f = fopen(path, "re"); - if (!f) - return ECGROUPNOTEXIST; - - while (fgets(buf, sizeof(buf), f)) { - if (!strncmp(buf, "Uid:", 4)) { - if (sscanf((buf + strlen("Uid:") + 1), "%d%d%d%d", - &ruid, euid, &suid, &fsuid) != 4) - break; - cgroup_dbg("Scanned proc values are %d %d %d %d\n", - ruid, *euid, suid, fsuid); - found_euid = true; - } else if (!strncmp(buf, "Gid:", 4)) { - if (sscanf((buf + strlen("Gid:") + 1), "%d%d%d%d", - &rgid, egid, &sgid, &fsgid) != 4) - break; - cgroup_dbg("Scanned proc values are %d %d %d %d\n", - rgid, *egid, sgid, fsgid); - found_egid = true; - } - if (found_euid && found_egid) - break; - } - fclose(f); - if (!found_euid || !found_egid) { - /* - * This method doesn't match the file format of - * /proc//status. The format has been changed - * and we should catch up the change. - */ - cgroup_warn("Warning: invalid file format of /proc/%d/status\n", - pid); - return ECGFAIL; - } - return 0; -} - -/** - * Given a pid, this function will return the controllers and cgroups that - * the pid is a member of. The caller is expected to allocate the - * controller_list[] and cgroup_list[] arrays as well as null each entry in - * the arrays. This function will allocate the necessary memory for each - * string within the arrays. - * - * @param pid The process id - * @param cgroup_list[] An array of char pointers to hold the cgroups - * @param controller_list[] An array of char pointers to hold the list - * of controllers - * @param list_len The size of the arrays - */ -STATIC int cg_get_cgroups_from_proc_cgroups(pid_t pid, char *cgroup_list[], - char *controller_list[], - int list_len) -{ - char path[FILENAME_MAX]; - char buf[4092]; - char *stok_buff = NULL; - int ret = 0; - size_t buff_len; - int idx = 0; - FILE *f; - -#ifdef UNIT_TEST - sprintf(path, "%s", TEST_PROC_PID_CGROUP_FILE); -#else - sprintf(path, "/proc/%d/cgroup", pid); -#endif - f = fopen(path, "re"); - if (!f) - return ECGROUPNOTEXIST; - - while (fgets(buf, sizeof(buf), f)) { - /* - * Each line in /proc/{pid}/cgroup is like the following: - * - * {cg#}:{controller}:{cgname} - * - * e.g. - * 7:devices:/user.slice - */ - - /* read in the cgroup number. we don't care about it */ - stok_buff = strtok(buf, ":"); - /* read in the controller name */ - stok_buff = strtok(NULL, ":"); - - /* - * after this point, we have allocated memory. if we return - * an error code after this, it's up to us to free the - * memory we allocated - */ - controller_list[idx] = strndup(stok_buff, - strlen(stok_buff) + 1); - - /* read in the cgroup name */ - stok_buff = strtok(NULL, ":"); - - if (stok_buff == NULL) { - /* - * An empty controller is reported on some kernels. - * It may look like this: - * 0::/user.slice/user-1000.slice/session-1.scope - * - * Ignore this controller and move on. Note that we - * need to free the controller list entry we made. - */ - free(controller_list[idx]); - controller_list[idx] = NULL; - continue; - } - - buff_len = strlen(stok_buff); - if (stok_buff[buff_len - 1] == '\n') - /* Don't copy the trailing newline char */ - buff_len--; - - /* read in the cgroup name */ - if (buff_len > 1) { - /* - * Strip off the leading '/' for every cgroup but - * the root cgroup - */ - cgroup_list[idx] = malloc(buff_len); - snprintf(cgroup_list[idx], buff_len, "%s", - &stok_buff[1]); - } else { - /* - * Retain the leading '/' since we're in the root - * cgroup - */ - cgroup_list[idx] = strndup(stok_buff, buff_len); - } - - idx++; - if (idx >= list_len) { - cgroup_warn("Maximum mount elements reached. " - "Consider increasing MAX_MNT_ELEMENTS\n"); - break; - } - } - fclose(f); - return ret; -} - -/** - * Get process name from /proc//status file. - * @param pid: The process id - * @param pname_status : The process name - * @return 0 on success, > 0 on error. - */ -static int cg_get_procname_from_proc_status(pid_t pid, char **procname_status) -{ - int ret = ECGFAIL; - int len; - FILE *f; - char path[FILENAME_MAX]; - char buf[4092]; - - sprintf(path, "/proc/%d/status", pid); - f = fopen(path, "re"); - if (!f) - return ECGROUPNOTEXIST; - - while (fgets(buf, sizeof(buf), f)) { - if (!strncmp(buf, "Name:", 5)) { - len = strlen(buf); - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - *procname_status = strdup(buf + strlen("Name:") + 1); - if (*procname_status == NULL) { - last_errno = errno; - ret = ECGOTHER; - break; - } - ret = 0; - break; - } - } - fclose(f); - return ret; -} - -/** - * Get process name from /proc//cmdline file. - * This function is mainly for getting a script name (shell, perl, - * etc). A script name is written into the second or later argument - * of /proc//cmdline. This function gets each argument and - * compares it to a process name taken from /proc//status. - * @param pid: The process id - * @param pname_status : The process name taken from /proc//status - * @param pname_cmdline: The process name taken from /proc//cmdline - * @return 0 on success, > 0 on error. - */ -static int cg_get_procname_from_proc_cmdline(pid_t pid, - const char *pname_status, char **pname_cmdline) -{ - FILE *f; - int ret = ECGFAIL; - int c = 0; - int len = 0; - char path[FILENAME_MAX]; - char buf_pname[FILENAME_MAX]; - char buf_cwd[FILENAME_MAX]; - - memset(buf_cwd, '\0', sizeof(buf_cwd)); - sprintf(path, "/proc/%d/cwd", pid); - if (readlink(path, buf_cwd, sizeof(buf_cwd)) < 0) - return ECGROUPNOTEXIST; - - sprintf(path, "/proc/%d/cmdline", pid); - f = fopen(path, "re"); - if (!f) - return ECGROUPNOTEXIST; - - while (c != EOF) { - c = fgetc(f); - if ((c != EOF) && (c != '\0') && (len < FILENAME_MAX - 1)) { - buf_pname[len] = c; - len++; - continue; - } - buf_pname[len] = '\0'; - - if (len == FILENAME_MAX - 1) - while ((c != EOF) && (c != '\0')) - c = fgetc(f); - - /* - * The taken process name from /proc//status is - * shortened to 15 characters if it is over. So the - * name should be compared by its length. - */ - if (strncmp(pname_status, basename(buf_pname), - TASK_COMM_LEN - 1)) { - len = 0; - continue; - } - if (buf_pname[0] == '/') { - *pname_cmdline = strdup(buf_pname); - if (*pname_cmdline == NULL) { - last_errno = errno; - ret = ECGOTHER; - break; - } - ret = 0; - break; - } else { - strcat(buf_cwd, "/"); - strcat(buf_cwd, buf_pname); - if (!realpath(buf_cwd, path)) { - last_errno = errno; - ret = ECGOTHER; - break; - } - *pname_cmdline = strdup(path); - if (*pname_cmdline == NULL) { - last_errno = errno; - ret = ECGOTHER; - break; - } - ret = 0; - break; - } - } - fclose(f); - return ret; -} - -/** - * Get a process name from /proc file system. - * This function allocates memory for a process name, writes a process - * name onto it. So a caller should free the memory when unusing it. - * @param pid: The process id - * @param procname: The process name - * @return 0 on success, > 0 on error. - */ -int cgroup_get_procname_from_procfs(pid_t pid, char **procname) -{ - int ret; - char *pname_status; - char *pname_cmdline; - char path[FILENAME_MAX]; - char buf[FILENAME_MAX]; - - ret = cg_get_procname_from_proc_status(pid, &pname_status); - if (ret) - return ret; - - /* - * Get the full patch of process name from /proc//exe. - */ - memset(buf, '\0', sizeof(buf)); - sprintf(path, "/proc/%d/exe", pid); - if (readlink(path, buf, sizeof(buf)) < 0) { - /* - * readlink() fails if a kernel thread, and a process - * name is taken from /proc//status. - */ - *procname = pname_status; - return 0; - } - if (!strncmp(pname_status, basename(buf), TASK_COMM_LEN - 1)) { - /* - * The taken process name from /proc//status is - * shortened to 15 characters if it is over. So the - * name should be compared by its length. - */ - free(pname_status); - *procname = strdup(buf); - if (*procname == NULL) { - last_errno = errno; - return ECGOTHER; - } - return 0; - } - - /* - * The above strncmp() is not 0 if a shell script, because - * /proc//exe links a shell command (/bin/bash etc.) - * and the pname_status represents a shell script name. - * Then the full path of a shell script is taken from - * /proc//cmdline. - */ - ret = cg_get_procname_from_proc_cmdline(pid, pname_status, - &pname_cmdline); - if (!ret) { - *procname = pname_cmdline; - free(pname_status); - return 0; - } - - /* - * The above strncmp() is not 0 also if executing a symbolic link, - * /proc/pid/exe points to real executable name then. - * Return it as the last resort. - */ - free(pname_status); - *procname = strdup(buf); - if (*procname == NULL) { - last_errno = errno; - return ECGOTHER; - } - return 0; -} - -int cgroup_register_unchanged_process(pid_t pid, int flags) -{ - int sk; - int ret = 1; - char buff[sizeof(CGRULE_SUCCESS_STORE_PID)]; - struct sockaddr_un addr; - - sk = socket(PF_UNIX, SOCK_STREAM, 0); - if (sk < 0) - return 1; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, CGRULE_CGRED_SOCKET_PATH); - - if (connect(sk, (struct sockaddr *)&addr, - sizeof(addr.sun_family) + strlen(CGRULE_CGRED_SOCKET_PATH)) < 0) { - /* If the daemon does not work, this function returns 0 - * as success. */ - ret = 0; - goto close; - } - if (write(sk, &pid, sizeof(pid)) < 0) - goto close; - - if (write(sk, &flags, sizeof(flags)) < 0) - goto close; - - if (read(sk, buff, sizeof(buff)) < 0) - goto close; - - if (strncmp(buff, CGRULE_SUCCESS_STORE_PID, sizeof(buff))) - goto close; - - ret = 0; -close: - close(sk); - return ret; -} - -int cgroup_get_subsys_mount_point(const char *controller, char **mount_point) -{ - int i; - int ret = ECGROUPNOTEXIST; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - - if (!controller) - return ECGINVAL; - - pthread_rwlock_rdlock(&cg_mount_table_lock); - for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { - if (strncmp(cg_mount_table[i].name, controller, FILENAME_MAX)) - continue; - - *mount_point = strdup(cg_mount_table[i].mount.path); - - if (!*mount_point) { - last_errno = errno; - ret = ECGOTHER; - goto out_exit; - } - - ret = 0; - break; - } -out_exit: - pthread_rwlock_unlock(&cg_mount_table_lock); - return ret; -} - - -int cgroup_get_all_controller_end(void **handle) -{ - FILE *proc_cgroup = (FILE *) *handle; - - if (!proc_cgroup) - return ECGINVAL; - - fclose(proc_cgroup); - *handle = NULL; - - return 0; -} - - -int cgroup_get_all_controller_next(void **handle, struct controller_data *info) -{ - FILE *proc_cgroup = (FILE *) *handle; - int err = 0; - int hierarchy, num_cgroups, enabled; - char subsys_name[FILENAME_MAX]; - - if (!proc_cgroup) - return ECGINVAL; - - if (!info) - return ECGINVAL; - - err = fscanf(proc_cgroup, "%s %d %d %d\n", subsys_name, - &hierarchy, &num_cgroups, &enabled); - - if (err != 4) - return ECGEOF; - - strncpy(info->name, subsys_name, FILENAME_MAX); - info->name[FILENAME_MAX-1] = '\0'; - info->hierarchy = hierarchy; - info->num_cgroups = num_cgroups; - info->enabled = enabled; - - return 0; -} - - -int cgroup_get_all_controller_begin(void **handle, struct controller_data *info) -{ - FILE *proc_cgroup = NULL; - char buf[FILENAME_MAX]; - int ret; - - if (!info) - return ECGINVAL; - - proc_cgroup = fopen("/proc/cgroups", "re"); - if (!proc_cgroup) { - last_errno = errno; - return ECGOTHER; - } - - if (!fgets(buf, FILENAME_MAX, proc_cgroup)) { - last_errno = errno; - fclose(proc_cgroup); - *handle = NULL; - return ECGOTHER; - } - *handle = proc_cgroup; - - ret = cgroup_get_all_controller_next(handle, info); - if (ret != 0) { - fclose(proc_cgroup); - *handle = NULL; - } - return ret; -} - -static int pid_compare(const void *a, const void *b) -{ - const pid_t *pid1, *pid2; - - pid1 = (pid_t *) a; - pid2 = (pid_t *) b; - - return (*pid1 - *pid2); -} - -/* - *pids needs to be completely uninitialized so that we can set it up - * - * Caller must free up pids. - */ -int cgroup_get_procs(char *name, char *controller, pid_t **pids, int *size) -{ - char cgroup_path[FILENAME_MAX]; - FILE *procs; - pid_t *tmp_list; - int tot_procs = 16; - int n = 0; - int err; - - cg_build_path(name, cgroup_path, controller); - strncat(cgroup_path, "/cgroup.procs", FILENAME_MAX-strlen(cgroup_path)); - - /* - * This kernel does have support for cgroup.procs - */ - if (access(cgroup_path, F_OK)) - return ECGROUPUNSUPP; - - /* - * Keep doubling the memory allocated if needed - */ - tmp_list= malloc(sizeof(pid_t) * tot_procs); - if (!tmp_list) { - last_errno = errno; - return ECGOTHER; - } - - procs = fopen(cgroup_path, "r"); - if (!procs) { - last_errno = errno; - free(tmp_list); - *pids = NULL; - *size = 0; - return ECGOTHER; - } - - while (!feof(procs)) { - while (!feof(procs) && n < tot_procs) { - pid_t pid; - err = fscanf(procs, "%u", &pid); - if (err == EOF) - break; - tmp_list[n] = pid; - n++; - } - if (!feof(procs)) { - pid_t *orig_list = tmp_list; - tot_procs *= 2; - tmp_list = realloc(tmp_list, sizeof(pid_t) * tot_procs); - if (!tmp_list) { - last_errno = errno; - fclose(procs); - free(orig_list); - *pids = NULL; - *size = 0; - return ECGOTHER; - } - } - } - - fclose(procs); - - *size = n; - - qsort(tmp_list, n, sizeof(pid_t), &pid_compare); - - *pids = tmp_list; - - return 0; -} - - -int cgroup_dictionary_create(struct cgroup_dictionary **dict, - int flags) -{ - if (!dict) - return ECGINVAL; - *dict = (struct cgroup_dictionary *) calloc( - 1, sizeof(struct cgroup_dictionary)); - - if (!*dict) { - last_errno = errno; - return ECGOTHER; - } - (*dict)->flags = flags; - return 0; -} - - -int cgroup_dictionary_add(struct cgroup_dictionary *dict, - const char *name, const char *value) -{ - struct cgroup_dictionary_item *it; - - if (!dict) - return ECGINVAL; - - it = (struct cgroup_dictionary_item *) malloc( - sizeof(struct cgroup_dictionary_item)); - if (!it) { - last_errno = errno; - return ECGOTHER; - } - - it->next = NULL; - it->name = name; - it->value = value; - - if (dict->tail) { - dict->tail->next = it; - dict->tail = it; - } else { - /* it is the first item */ - dict->tail = it; - dict->head = it; - } - return 0; -} - -int cgroup_dictionary_free(struct cgroup_dictionary *dict) -{ - struct cgroup_dictionary_item *it; - - if (!dict) - return ECGINVAL; - - it = dict->head; - while (it) { - struct cgroup_dictionary_item *del = it; - it = it->next; - if (!(dict->flags & CG_DICT_DONT_FREE_ITEMS)) { - free((void *)del->value); - free((void *)del->name); - } - free(del); - } - - free(dict); - return 0; -} - -int cgroup_dictionary_iterator_begin(struct cgroup_dictionary *dict, - void **handle, const char **name, const char **value) -{ - struct cgroup_dictionary_iterator *iter; - - *handle = NULL; - - if (!dict) - return ECGINVAL; - - iter = (struct cgroup_dictionary_iterator *) malloc( - sizeof(struct cgroup_dictionary_iterator)); - if (!iter) { - last_errno = errno; - return ECGOTHER; - } - - iter->item = dict->head; - *handle = iter; - return cgroup_dictionary_iterator_next(handle, name, value); -} - -int cgroup_dictionary_iterator_next(void **handle, - const char **name, const char **value) -{ - struct cgroup_dictionary_iterator *iter; - - if (!handle) - return ECGINVAL; - - iter = *handle; - - if (!iter) - return ECGINVAL; - - if (!iter->item) - return ECGEOF; - - *name = iter->item->name; - *value = iter->item->value; - iter->item = iter->item->next; - return 0; -} - -void cgroup_dictionary_iterator_end(void **handle) -{ - if (!handle) - return; - - free(*handle); - *handle = NULL; -} - -int cgroup_get_subsys_mount_point_begin(const char *controller, void **handle, - char *path) -{ - int i; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - if (!handle || !path || !controller) - return ECGINVAL; - - - for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) - if (strcmp(controller, cg_mount_table[i].name) == 0) - break; - - if (cg_mount_table[i].name[0] == '\0') { - /* the controller is not mounted at all */ - *handle = NULL; - *path = '\0'; - return ECGEOF; - } - - /* - * 'handle' is pointer to struct cg_mount_point, which should be - * returned next. - */ - *handle = cg_mount_table[i].mount.next; - strcpy(path, cg_mount_table[i].mount.path); - return 0; -} - -int cgroup_get_subsys_mount_point_next(void **handle, - char *path) -{ - struct cg_mount_point *it; - - if (!cgroup_initialized) - return ECGROUPNOTINITIALIZED; - if (!handle || !path) - return ECGINVAL; - - it = *handle; - if (!it) { - *handle = NULL; - *path = '\0'; - return ECGEOF; - } - - *handle = it->next; - strcpy(path, it->path); - return 0; -} - -int cgroup_get_subsys_mount_point_end(void **handle) -{ - return 0; -} - - diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am deleted file mode 100644 index caf388ff..00000000 --- a/src/bindings/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -SUBDIRS = . -INCLUDES = -I$(top_srcdir)/include - -lib_LTLIBRARIES = _libcgroup.la -_libcgroup_la_SOURCES = libcgroup.c -_libcgroup_la_LDFLAGS = $(shell python-config --ldflags) -module -avoid-version -_libcgroup_la_CFLAGS = $(shell python-config --cflags) -_libcgroup_la_LIBADD = $(top_builddir)/src/.libs/libcgroup.la -SWIG=swig - - -libcgroup.c: libcgroup.p $(top_srcdir)/include/libcgroup.h - cp libcgroup.p libcgroup.i - $(CC) $(INCLUDES) -DSWIG -E $(top_srcdir)/include/libcgroup.h >> libcgroup.i - $(SWIG) -python -o libcgroup.c libcgroup.i diff --git a/src/bindings/libcgroup.p b/src/bindings/libcgroup.p deleted file mode 100644 index ebbbcdc2..00000000 --- a/src/bindings/libcgroup.p +++ /dev/null @@ -1,29 +0,0 @@ -%module libcgroup -%{ -#include "libcgroup.h" -%} - -#ifdef __cplusplus -#define __BEGIN_DECLS extern "C" { -#define __END_DECLS } -#else -#define __BEGIN_DECLS -#define __END_DECLS -#endif - -%include typemaps.i -%include cpointer.i -%pointer_functions(int, intp); -%typemap (in) void** (void *temp) { - void *arg; - if ((arg = PyCObject_AsVoidPtr($input)) != NULL) { - $1 = &arg; - } else - $1 = &temp; -} - -%typemap (argout) void** { - PyObject *obj = PyCObject_FromVoidPtr(*$1, NULL); - $result = PyTuple_Pack(2, $result, obj); -} - diff --git a/src/bindings/tests/stat.py b/src/bindings/tests/stat.py deleted file mode 100644 index 3cfdb246..00000000 --- a/src/bindings/tests/stat.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python - -from libcgroup import * -from ctypes import * - -ret = cgroup_init() -if (ret != 0): - print cgroup_strerror(ret) - exit(1) - -# -# Add the correct controllers based on the mount point -# -cg_stat = cgroup_stat() -tree_handle = c_void_p() -info = cgroup_file_info() -lvl = new_intp() -ret1, tree_handle = cgroup_walk_tree_begin("memory", "/", 0, tree_handle, info, lvl) -root_len = len(info.full_path) - 1 -while ret1 != ECGEOF: - if (info.type == CGROUP_FILE_TYPE_DIR): - dir = info.full_path[root_len:] - print "\nDirectory %s\n" %(dir) - - p = c_void_p() - ret, p = cgroup_read_stats_begin("memory", dir, p, cg_stat) - while ret != ECGEOF: - print "%s:%s" %(cg_stat.name, cg_stat.value.strip('\n')) - ret, p = cgroup_read_stats_next(p, cg_stat) - - cgroup_read_stats_end(p) - ret1, tree_handle = cgroup_walk_tree_next(0, tree_handle, info, intp_value(lvl)) - -cgroup_walk_tree_end(tree_handle) -delete_intp(lvl) diff --git a/src/config.c b/src/config.c deleted file mode 100644 index 3ffa2637..00000000 --- a/src/config.c +++ /dev/null @@ -1,1887 +0,0 @@ -/* - * Copyright IBM Corporation. 2007 - * - * Authors: Balbir Singh - * Dhaval Giani - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * TODOs: - * 1. Implement our own hashing scheme - * - * Code initiated and designed by Balbir Singh. All faults are most likely - * his mistake. - * - * Cleanup and changes to use the "official" structures and functions made - * by Dhaval Giani. All faults will still be Balbir's mistake :) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "tools/tools-common.h" - -unsigned int MAX_CGROUPS = 64; /* NOTE: This value changes dynamically */ -unsigned int MAX_TEMPLATES = 64; - /* NOTE: This value changes dynamically */ - -enum tc_switch_t { - CGROUP, - TEMPLATE, -}; - -extern FILE *yyin; -extern int yyparse(void); - -static struct cgroup default_group; -static int default_group_set = 0; - -/* - * The basic global data structures. - * - * config_mount_table -> Where what controller is mounted - * table_index -> Where in the table are we. - * config_table_lock -> Serializing access to config_mount_table. - * cgroup_table -> Which cgroups have to be created. - * cgroup_table_index -> Where in the cgroup_table we are. - */ -static struct cg_mount_table_s config_mount_table[CG_CONTROLLER_MAX]; -static struct cg_mount_table_s config_namespace_table[CG_CONTROLLER_MAX]; -static int config_table_index; -static int namespace_table_index; -static pthread_rwlock_t config_table_lock = PTHREAD_RWLOCK_INITIALIZER; -static pthread_rwlock_t namespace_table_lock = PTHREAD_RWLOCK_INITIALIZER; -static struct cgroup *config_cgroup_table; -static int cgroup_table_index; - -/* - * template structures filled by cgroup_parse_config when the configuration - * file is parsing (analogous to config_cgroup_table and cgroup_table_index - * for cgroups) - */ -static struct cgroup *config_template_table; -static int config_template_table_index; - -/* - * template structures used for templates cache, config_template_table and - * cgroup_template_table_index are rewritten in each cgroup_parse_config - * thus not only if we want to reload template cache - */ -static struct cgroup *template_table; -static int template_table_index; -static struct cgroup_string_list *template_files; - - -/* - * Needed for the type while mounting cgroupfs. - */ -#define CGROUP_FILESYSTEM "cgroup" - -/* - * NOTE: All these functions return 1 on success - * and not 0 as is the library convention - */ - -/* - * This call just sets the name of the cgroup. It will - * always be called in the end, because the parser will - * work bottom up. It works for cgroup and templates tables - * based on flag variable: - * CGROUP ... cgroup - * TEMPLATE ... template - */ -int config_insert_cgroup(char *cg_name, int flag) -{ - - struct cgroup *config_cgroup; - struct cgroup *config_table; - unsigned int *max; - int *table_index; - - switch (flag) { - case CGROUP: - table_index = &cgroup_table_index; - config_table = config_cgroup_table; - max = &MAX_CGROUPS; - break; - case TEMPLATE: - table_index = &config_template_table_index; - config_table = config_template_table; - max = &MAX_TEMPLATES; - break; - default: - return 0; - } - - if (*table_index >= *max - 1) { - struct cgroup *newblk; - unsigned int oldlen; - - if (*max >= INT_MAX) { - last_errno = ENOMEM; - return 0; - } - oldlen = *max; - *max *= 2; - newblk = realloc(config_table, (*max * sizeof(struct cgroup))); - if (!newblk) { - last_errno = ENOMEM; - return 0; - } - - memset(newblk + oldlen, 0, (*max - oldlen) * - sizeof(struct cgroup)); - init_cgroup_table(newblk + oldlen, *max - oldlen); - config_table = newblk; - switch (flag) { - case CGROUP: - config_cgroup_table = config_table; - break; - case TEMPLATE: - config_template_table = config_table; - break; - default: - return 0; - } - cgroup_dbg("maximum %d\n", *max); - cgroup_dbg("reallocated config_table to %p\n", - config_table); - } - - config_cgroup = &config_table[*table_index]; - strncpy(config_cgroup->name, cg_name, FILENAME_MAX - 1); - - /* - * Since this will be the last part to be parsed. - */ - *table_index = *table_index + 1; - free(cg_name); - return 1; -} - -/* - * This call just sets the name of the cgroup. It will - * always be called in the end, because the parser will - * work bottom up. - */ -int cgroup_config_insert_cgroup(char *cg_name) -{ - int ret; - - ret = config_insert_cgroup(cg_name, CGROUP); - return ret; -} - -/* - * This call just sets the name of the template. It will - * always be called in the end, because the parser will - * work bottom up. - */ -int template_config_insert_cgroup(char *cg_name) -{ - int ret; - - ret = config_insert_cgroup(cg_name, TEMPLATE); - return ret; -} - -/* - * This function sets the various controller's control - * files. It will always append values for config_cgroup/template_table_index - * entry in the config_cgroup/template_table. The index is incremented in - * cgroup/template_config_insert_cgroup. - * flag variable switch between cgroup/templates variables: - * CGROUP ... cgroup - * TEMPLATE ... template - */ -int config_parse_controller_options(char *controller, - struct cgroup_dictionary *values, int flag) -{ - const char *name, *value; - struct cgroup_controller *cgc; - int error; - struct cgroup *config_cgroup; - void *iter = NULL; - int *table_index; - - switch (flag) { - case CGROUP: - table_index = &cgroup_table_index; - config_cgroup = - &config_cgroup_table[*table_index]; - break; - case TEMPLATE: - table_index = &config_template_table_index; - config_cgroup = - &config_template_table[*table_index]; - break; - default: - return 0; - } - - cgroup_dbg("Adding controller %s\n", controller); - cgc = cgroup_add_controller(config_cgroup, controller); - - if (!cgc) - goto parse_error; - - /* - * Did we just specify the controller to create the correct - * set of directories, without setting any values? - */ - if (!values) - goto done; - - error = cgroup_dictionary_iterator_begin(values, &iter, &name, &value); - while (error == 0) { - cgroup_dbg("[1] name value pair being processed is %s=%s\n", - name, value); - if (!name) - goto parse_error; - error = cgroup_add_value_string(cgc, name, value); - if (error) - goto parse_error; - error = cgroup_dictionary_iterator_next(&iter, &name, &value); - } - cgroup_dictionary_iterator_end(&iter); - iter = NULL; - - if (error != ECGEOF) - goto parse_error; - -done: - free(controller); - return 1; - -parse_error: - free(controller); - cgroup_dictionary_iterator_end(&iter); - cgroup_delete_cgroup(config_cgroup, 1); - *table_index = *table_index - 1; - return 0; -} - -/* This function sets the various controller's control - * files. It will always append values for cgroup_table_index - * entry in the cgroup_table. The index is incremented in - * cgroup_config_insert_cgroup - */ - -int cgroup_config_parse_controller_options(char *controller, - struct cgroup_dictionary *values) -{ - int ret; - - ret = config_parse_controller_options(controller, values, CGROUP); - return ret; -} - -/* This function sets the various controller's control - * files. It will always append values for config_template_table_index - * entry in the config_template_table. The index is incremented in - * template_config_insert_cgroup - */ - -int template_config_parse_controller_options(char *controller, - struct cgroup_dictionary *values) -{ - int ret; - - ret = config_parse_controller_options(controller, values, TEMPLATE); - return ret; -} - -/* - * Sets the tasks file's uid and gid for cgroup and templates tables - * based on flag variable: - * CGROUP ... cgroup - * TEMPLATE ... template - */ -int config_group_task_perm(char *perm_type, char *value, int flag) -{ - struct passwd *pw, *pw_buffer; - struct group *group, *group_buffer; - long val = atoi(value); - char buffer[CGROUP_BUFFER_LEN]; - struct cgroup *config_cgroup; - int table_index; - - switch (flag) { - case CGROUP: - table_index = cgroup_table_index; - config_cgroup = - &config_cgroup_table[table_index]; - break; - case TEMPLATE: - table_index = config_template_table_index; - config_cgroup = - &config_template_table[table_index]; - break; - default: - return 0; - } - - if (!strcmp(perm_type, "uid")) { - if (!val) { - pw = (struct passwd *) malloc(sizeof(struct passwd)); - - if (!pw) - goto group_task_error; - - getpwnam_r(value, pw, buffer, CGROUP_BUFFER_LEN, - &pw_buffer); - if (pw_buffer == NULL) { - free(pw); - goto group_task_error; - } - - val = pw->pw_uid; - free(pw); - } - config_cgroup->tasks_uid = val; - } - - if (!strcmp(perm_type, "gid")) { - if (!val) { - group = (struct group *) malloc(sizeof(struct group)); - - if (!group) - goto group_task_error; - - getgrnam_r(value, group, buffer, - CGROUP_BUFFER_LEN, &group_buffer); - - if (group_buffer == NULL) { - free(group); - goto group_task_error; - } - - val = group->gr_gid; - free(group); - } - config_cgroup->tasks_gid = val; - } - - if (!strcmp(perm_type, "fperm")) { - char *endptr; - val = strtol(value, &endptr, 8); - if (*endptr) - goto group_task_error; - config_cgroup->task_fperm = val; - } - - free(perm_type); - free(value); - return 1; - -group_task_error: - free(perm_type); - free(value); - cgroup_delete_cgroup(config_cgroup, 1); - table_index--; - return 0; -} - -/* - * Sets the tasks file's uid and gid - */ -int cgroup_config_group_task_perm(char *perm_type, char *value) -{ - int ret; - - ret = config_group_task_perm(perm_type, value, CGROUP); - return ret; -} - -/* - * Sets the tasks file's uid and gid for templates - */ -int template_config_group_task_perm(char *perm_type, char *value) -{ - int ret; - - ret = config_group_task_perm(perm_type, value, TEMPLATE); - return ret; -} - -/* - * Sets the admin file's uid and gid for cgroup and templates tables - * based on flag variable: - * CGROUP ... cgroup - * TEMPLATE ... templates - */ -int config_group_admin_perm(char *perm_type, char *value, int flag) -{ - struct passwd *pw, *pw_buffer; - struct group *group, *group_buffer; - struct cgroup *config_cgroup; - long val = atoi(value); - char buffer[CGROUP_BUFFER_LEN]; - int table_index; - - switch (flag) { - case CGROUP: - table_index = cgroup_table_index; - config_cgroup = &config_cgroup_table[table_index]; - break; - case TEMPLATE: - table_index = config_template_table_index; - config_cgroup = &config_template_table[table_index]; - break; - default: - return 0; - } - - - if (!strcmp(perm_type, "uid")) { - if (!val) { - pw = (struct passwd *) malloc(sizeof(struct passwd)); - - if (!pw) - goto admin_error; - - getpwnam_r(value, pw, buffer, CGROUP_BUFFER_LEN, - &pw_buffer); - if (pw_buffer == NULL) { - free(pw); - goto admin_error; - } - - val = pw->pw_uid; - free(pw); - } - config_cgroup->control_uid = val; - } - - if (!strcmp(perm_type, "gid")) { - if (!val) { - group = (struct group *) malloc(sizeof(struct group)); - - if (!group) - goto admin_error; - - getgrnam_r(value, group, buffer, - CGROUP_BUFFER_LEN, &group_buffer); - - if (group_buffer == NULL) { - free(group); - goto admin_error; - } - - val = group->gr_gid; - free(group); - } - config_cgroup->control_gid = val; - } - - if (!strcmp(perm_type, "fperm")) { - char *endptr; - val = strtol(value, &endptr, 8); - if (*endptr) - goto admin_error; - config_cgroup->control_fperm = val; - } - - if (!strcmp(perm_type, "dperm")) { - char *endptr; - val = strtol(value, &endptr, 8); - if (*endptr) - goto admin_error; - config_cgroup->control_dperm = val; - } - - free(perm_type); - free(value); - return 1; - -admin_error: - free(perm_type); - free(value); - cgroup_delete_cgroup(config_cgroup, 1); - table_index--; - return 0; -} - -/* - * Set the control file's uid and gid - */ -int cgroup_config_group_admin_perm(char *perm_type, char *value) -{ - int ret; - - ret = config_group_admin_perm(perm_type, value, CGROUP); - return ret; -} - -/* - * Set the control file's uid and gid for templates - */ -int template_config_group_admin_perm(char *perm_type, char *value) -{ - int ret; - - ret = config_group_admin_perm(perm_type, value, TEMPLATE); - return ret; -} - -/* - * The moment we have found the controller's information - * insert it into the config_mount_table. - */ -int cgroup_config_insert_into_mount_table(char *name, char *mount_point) -{ - int i; - - if (config_table_index >= CG_CONTROLLER_MAX) - return 0; - - pthread_rwlock_wrlock(&config_table_lock); - - /* - * Merge controller names with the same mount point - */ - for (i = 0; i < config_table_index; i++) { - if (strcmp(config_mount_table[i].mount.path, - mount_point) == 0) { - char *cname = config_mount_table[i].name; - strncat(cname, ",", FILENAME_MAX - strlen(cname) - 1); - strncat(cname, name, - FILENAME_MAX - strlen(cname) - 1); - goto done; - } - } - - strcpy(config_mount_table[config_table_index].name, name); - strcpy(config_mount_table[config_table_index].mount.path, mount_point); - config_mount_table[config_table_index].mount.next = NULL; - config_table_index++; -done: - pthread_rwlock_unlock(&config_table_lock); - free(name); - free(mount_point); - return 1; -} - -/* - * Cleanup all the data from the config_mount_table - */ -void cgroup_config_cleanup_mount_table(void) -{ - memset(&config_mount_table, 0, - sizeof(struct cg_mount_table_s) * CG_CONTROLLER_MAX); -} - -/* - * The moment we have found the controller's information - * insert it into the config_mount_table. - */ -int cgroup_config_insert_into_namespace_table(char *name, char *nspath) -{ - if (namespace_table_index >= CG_CONTROLLER_MAX) - return 0; - - pthread_rwlock_wrlock(&namespace_table_lock); - - strcpy(config_namespace_table[namespace_table_index].name, name); - strcpy(config_namespace_table[namespace_table_index].mount.path, - nspath); - config_namespace_table[namespace_table_index].mount.next = NULL; - namespace_table_index++; - - pthread_rwlock_unlock(&namespace_table_lock); - free(name); - free(nspath); - return 1; -} - -/* - * Cleanup all the data from the config_mount_table - */ -void cgroup_config_cleanup_namespace_table(void) -{ - memset(&config_namespace_table, 0, - sizeof(struct cg_mount_table_s) * CG_CONTROLLER_MAX); -} - -/** - * Add necessary options for mount. Currently only 'none' option is added - * for mounts with only 'name=xxx' and without real controller. - */ -static int cgroup_config_ajdust_mount_options(struct cg_mount_table_s *mount, - unsigned long *flags) -{ - char *save = NULL; - char *opts = strdup(mount->name); - char *token; - int name_only = 1; - char *controller= NULL; - - *flags = 0; - if (opts == NULL) - return ECGFAIL; - - token = strtok_r(opts, ",", &save); - while (token != NULL) { - if (strncmp(token, "name=", 5) != 0) { - name_only = 0; - - if (!controller) { - controller = strdup(token); - if (controller == NULL) - break; - strncpy(mount->name, controller, sizeof(mount->name)); - mount->name[sizeof(mount->name)-1] = '\0'; - } - - if (strncmp(token, "nodev", strlen("nodev")) == 0) { - *flags |= MS_NODEV; - } - if (strncmp(token, "noexec", strlen("noexec")) == 0) { - *flags |= MS_NOEXEC; - } - if (strncmp(token, "nosuid", strlen("nosuid")) == 0) { - *flags |= MS_NOSUID; - } - - } else if (!name_only) { - /* - * We have controller + name=, do the right thing, since - * we are rebuuilding mount->name - */ - strncat(mount->name, ",", FILENAME_MAX - strlen(mount->name)-1); - strncat(mount->name, token, - FILENAME_MAX - strlen(mount->name) - 1); - } - token = strtok_r(NULL, ",", &save); - } - - free(controller); - free(opts); - - if (name_only) { - strncat(mount->name, ",", FILENAME_MAX - strlen(mount->name)-1); - strncat(mount->name, "none", - FILENAME_MAX - strlen(mount->name) - 1); - } - - return 0; -} - -/* - * Start mounting the mount table. - */ -static int cgroup_config_mount_fs(void) -{ - int ret; - struct stat buff; - int i; - int error; - unsigned long flags; - - for (i = 0; i < config_table_index; i++) { - struct cg_mount_table_s *curr = &(config_mount_table[i]); - - ret = stat(curr->mount.path, &buff); - - if (ret < 0 && errno != ENOENT) { - cgroup_err("Error: cannot access %s: %s\n", - curr->mount.path, strerror(errno)); - last_errno = errno; - error = ECGOTHER; - goto out_err; - } - - if (errno == ENOENT) { - ret = cg_mkdir_p(curr->mount.path); - if (ret) { - cgroup_err("Error: cannot create directory %s\n", - curr->mount.path); - error = ret; - goto out_err; - } - } else if (!S_ISDIR(buff.st_mode)) { - cgroup_err("Error: %s already exists but it is not a directory\n", - curr->mount.path); - errno = ENOTDIR; - last_errno = errno; - error = ECGOTHER; - goto out_err; - } - - error = cgroup_config_ajdust_mount_options(curr, &flags); - if (error) - goto out_err; - - ret = mount(CGROUP_FILESYSTEM, curr->mount.path, - CGROUP_FILESYSTEM, flags, curr->name); - - if (ret < 0) { - cgroup_err("Error: cannot mount %s to %s: %s\n", - curr->name, curr->mount.path, - strerror(errno)); - error = ECGMOUNTFAIL; - goto out_err; - } - } - return 0; -out_err: - /* - * If we come here, we have failed. Since we have touched only - * mountpoints prior to i, we shall operate on only them now. - */ - config_table_index = i; - return error; -} - -/* - * Actually create the groups once the parsing has been finished. - */ -static int cgroup_config_create_groups(void) -{ - int error = 0; - int i; - - for (i = 0; i < cgroup_table_index; i++) { - struct cgroup *cgroup = &config_cgroup_table[i]; - error = cgroup_create_cgroup(cgroup, 0); - cgroup_dbg("creating group %s, error %d\n", cgroup->name, - error); - if (error) - return error; - } - return error; -} - -/* - * Destroy the cgroups - */ -static int cgroup_config_destroy_groups(void) -{ - int error = 0, ret = 0; - int i; - - for (i = 0; i < cgroup_table_index; i++) { - struct cgroup *cgroup = &config_cgroup_table[i]; - error = cgroup_delete_cgroup_ext(cgroup, - CGFLAG_DELETE_RECURSIVE - | CGFLAG_DELETE_IGNORE_MIGRATION); - if (error) { - /* store the error, but continue deleting the rest */ - ret = error; - } - } - return ret; -} - -/* - * Unmount the controllers - */ -static int cgroup_config_unmount_controllers(void) -{ - int i; - int error; - - for (i = 0; i < config_table_index; i++) { - /* - * We ignore failures and ensure that all mounted - * containers are unmounted - */ - error = umount(config_mount_table[i].mount.path); - if (error < 0) - cgroup_dbg("Unmount failed\n"); - error = rmdir(config_mount_table[i].mount.path); - if (error < 0) - cgroup_dbg("rmdir failed\n"); - } - - return 0; -} - -static int config_validate_namespaces(void) -{ - int i; - char *namespace = NULL; - char *mount_path = NULL; - int j, subsys_count; - int error = 0; - - pthread_rwlock_wrlock(&cg_mount_table_lock); - for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { - /* - * If we get the path in the first run, then we - * are good, else we will need to go for two - * loops. This should be optimized in the future - */ - mount_path = cg_mount_table[i].mount.path; - - if (!mount_path) { - last_errno = errno; - error = ECGOTHER; - goto out_error; - } - - /* - * Setup the namespace for the subsystems having the same - * mount point. - */ - if (!cg_namespace_table[i]) { - namespace = NULL; - } else { - namespace = cg_namespace_table[i]; - if (!namespace) { - last_errno = errno; - error = ECGOTHER; - goto out_error; - } - } - - /* - * We want to handle all the subsytems that are mounted - * together. So initialize j to start from the next point in - * the mount table. - */ - - j = i + 1; - - /* - * Search through the mount table to locate which subsystems - * are mounted together. - */ - while (!strncmp(cg_mount_table[j].mount.path, mount_path, - FILENAME_MAX)) { - if (!namespace && cg_namespace_table[j]) { - /* In case namespace is not setup, set it up */ - namespace = cg_namespace_table[j]; - if (!namespace) { - last_errno = errno; - error = ECGOTHER; - goto out_error; - } - } - j++; - } - subsys_count = j; - - /* - * If there is no namespace, then continue on :) - */ - - if (!namespace) { - i = subsys_count - 1; - continue; - } - - /* - * Validate/setup the namespace - * If no namespace is specified, copy the namespace we have - * stored. If a namespace is specified, confirm if it is - * the same as we have stored. If not, we fail. - */ - for (j = i; j < subsys_count; j++) { - if (!cg_namespace_table[j]) { - cg_namespace_table[j] = strdup(namespace); - if (!cg_namespace_table[j]) { - last_errno = errno; - error = ECGOTHER; - goto out_error; - } - } else if (strcmp(namespace, cg_namespace_table[j])) { - error = ECGNAMESPACEPATHS; - goto out_error; - } - } - /* i++ in the for loop will increment it */ - i = subsys_count - 1; - } -out_error: - pthread_rwlock_unlock(&cg_mount_table_lock); - return error; -} - -/* - * Should always be called after cgroup_init() has been called - * - * NOT to be called outside the library. Is handled internally - * when we are looking to load namespace configurations. - * - * This function will order the namespace table in the same - * fashion as how the mou table is setup. - * - * Also it will setup namespaces for all the controllers mounted. - * In case a controller does not have a namespace assigned to it, it - * will set it to null. - */ -static int config_order_namespace_table(void) -{ - int i = 0; - int error = 0; - - pthread_rwlock_wrlock(&cg_mount_table_lock); - /* - * Set everything to NULL - */ - for (i = 0; i < CG_CONTROLLER_MAX; i++) - cg_namespace_table[i] = NULL; - - memset(cg_namespace_table, 0, - CG_CONTROLLER_MAX * sizeof(cg_namespace_table[0])); - - /* - * Now fill up the namespace table looking at the table we have - * otherwise. - */ - - for (i = 0; i < namespace_table_index; i++) { - int j; - int flag = 0; - for (j = 0; cg_mount_table[j].name[0] != '\0'; j++) { - if (strncmp(config_namespace_table[i].name, - cg_mount_table[j].name, FILENAME_MAX) == 0) { - - flag = 1; - - if (cg_namespace_table[j]) { - error = ECGNAMESPACEPATHS; - goto error_out; - } - - cg_namespace_table[j] = strdup( - config_namespace_table[i].mount.path); - if (!cg_namespace_table[j]) { - last_errno = errno; - error = ECGOTHER; - goto error_out; - } - } - } - if (!flag) - return ECGNAMESPACECONTROLLER; - } -error_out: - pthread_rwlock_unlock(&cg_mount_table_lock); - return error; -} - -/** - * Free all memory allocated during cgroup_parse_config(), namely - * config_cgroup_table and config_template_table. - */ -static void cgroup_free_config(void) -{ - int i; - if (config_cgroup_table) { - for (i = 0; i < cgroup_table_index; i++) - cgroup_free_controllers( - &config_cgroup_table[i]); - free(config_cgroup_table); - config_cgroup_table = NULL; - } - config_table_index = 0; - if (config_template_table) { - for (i = 0; i < config_template_table_index; i++) - cgroup_free_controllers( - &config_template_table[i]); - free(config_template_table); - config_template_table = NULL; - } - config_template_table_index = 0; -} - -/** - * Applies default permissions/uid/gid to all groups in config file. - */ -static void cgroup_config_apply_default() -{ - int i; - if (config_cgroup_table) { - for (i = 0; i < cgroup_table_index; i++) { - struct cgroup *c = &config_cgroup_table[i]; - - if (c->control_dperm == NO_PERMS) - c->control_dperm = default_group.control_dperm; - if (c->control_fperm == NO_PERMS) - c->control_fperm = default_group.control_fperm; - if (c->control_gid == NO_UID_GID) - c->control_gid = default_group.control_gid; - if (c->control_uid == NO_UID_GID) - c->control_uid = default_group.control_uid; - if (c->task_fperm == NO_PERMS) - c->task_fperm = default_group.task_fperm; - if (c->tasks_gid == NO_UID_GID) - c->tasks_gid = default_group.tasks_gid; - if (c->tasks_uid == NO_UID_GID) - c->tasks_uid = default_group.tasks_uid; - } - } -} - -static int cgroup_parse_config(const char *pathname) -{ - int ret; - - yyin = fopen(pathname, "re"); - - if (!yyin) { - cgroup_err("Error: failed to open file %s\n", pathname); - last_errno = errno; - return ECGOTHER; - } - - config_cgroup_table = calloc(MAX_CGROUPS, sizeof(struct cgroup)); - if (!config_cgroup_table) { - ret = ECGFAIL; - goto err; - } - - config_template_table = calloc(MAX_TEMPLATES, sizeof(struct cgroup)); - if (!config_template_table) { - ret = ECGFAIL; - goto err; - } - - /* Clear all internal variables so this function can be called twice. */ - init_cgroup_table(config_cgroup_table, MAX_CGROUPS); - init_cgroup_table(config_template_table, MAX_TEMPLATES); - memset(config_namespace_table, 0, sizeof(config_namespace_table)); - memset(config_mount_table, 0, sizeof(config_mount_table)); - config_table_index = 0; - namespace_table_index = 0; - cgroup_table_index = 0; - config_template_table_index = 0; - - if (!default_group_set) { - /* init the default cgroup */ - init_cgroup_table(&default_group, 1); - } - - /* - * Parser calls longjmp() on really fatal error (like out-of-memory). - */ - ret = setjmp(parser_error_env); - if (!ret) - ret = yyparse(); - if (ret) { - /* - * Either yyparse failed or longjmp() was called. - */ - cgroup_err("Error: failed to parse file %s\n", pathname); - ret = ECGCONFIGPARSEFAIL; - goto err; - } - -err: - if (yyin) - fclose(yyin); - if (ret) { - cgroup_free_config(); - } - return ret; -} - -int _cgroup_config_compare_groups(const void *p1, const void *p2) -{ - const struct cgroup *g1 = p1; - const struct cgroup *g2 = p2; - - return strcmp(g1->name, g2->name); -} - -static void cgroup_config_sort_groups() -{ - qsort(config_cgroup_table, cgroup_table_index, sizeof(struct cgroup), - _cgroup_config_compare_groups); -} - -/* - * The main function which does all the setup of the data structures - * and finally creates the cgroups - */ -int cgroup_config_load_config(const char *pathname) -{ - int error; - int namespace_enabled = 0; - int mount_enabled = 0; - int ret; - - ret = cgroup_parse_config(pathname); - if (ret != 0) - return ret; - - namespace_enabled = (config_namespace_table[0].name[0] != '\0'); - mount_enabled = (config_mount_table[0].name[0] != '\0'); - - /* - * The configuration should have namespace or mount, not both. - */ - if (namespace_enabled && mount_enabled) { - free(config_cgroup_table); - return ECGMOUNTNAMESPACE; - } - - error = cgroup_config_mount_fs(); - if (error) - goto err_mnt; - - error = cgroup_init(); - if (error == ECGROUPNOTMOUNTED && cgroup_table_index == 0 - && config_template_table_index == 0) { - /* - * The config file seems to be empty. - */ - error = 0; - goto err_mnt; - } - if (error) - goto err_mnt; - - /* - * The very first thing is to sort the namespace table. If we fail - * we unmount everything and get out. - */ - - error = config_order_namespace_table(); - if (error) - goto err_mnt; - - error = config_validate_namespaces(); - if (error) - goto err_mnt; - - cgroup_config_apply_default(); - error = cgroup_config_create_groups(); - cgroup_dbg("creating all cgroups now, error=%d\n", error); - if (error) - goto err_grp; - - cgroup_free_config(); - - return 0; -err_grp: - cgroup_config_destroy_groups(); -err_mnt: - cgroup_config_unmount_controllers(); - cgroup_free_config(); - return error; -} - -/* unmounts given mount, but only if it is empty */ -static int cgroup_config_try_unmount(struct cg_mount_table_s *mount_info) -{ - char *controller, *controller_list; - struct cg_mount_point *mount = &(mount_info->mount); - void *handle = NULL; - int ret, lvl; - struct cgroup_file_info info; - char *saveptr = NULL; - - /* parse the first controller name from list of controllers */ - controller_list = strdup(mount_info->name); - if (!controller_list) { - last_errno = errno; - return ECGOTHER; - } - controller = strtok_r(controller_list, ",", &saveptr); - if (!controller) { - free(controller_list); - return ECGINVAL; - } - - /* check if the hierarchy is empty */ - ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl); - free(controller_list); - if (ret == ECGCONTROLLEREXISTS) - return 0; - if (ret) - return ret; - /* skip the first found directory, it's '/' */ - ret = cgroup_walk_tree_next(0, &handle, &info, lvl); - /* find any other subdirectory */ - while (ret == 0) { - if (info.type == CGROUP_FILE_TYPE_DIR) - break; - ret = cgroup_walk_tree_next(0, &handle, &info, lvl); - } - cgroup_walk_tree_end(&handle); - if (ret == 0) { - cgroup_dbg("won't unmount %s: hieararchy is not empty\n", - mount_info->name); - return 0; /* the hieararchy is not empty */ - } - if (ret != ECGEOF) - return ret; - - - /* - * ret must be ECGEOF now = there is only root group in the hierarchy - * -> unmount all mount points. - */ - ret = 0; - while (mount) { - int err; - cgroup_dbg("unmounting %s at %s\n", mount_info->name, - mount->path); - err = umount(mount->path); - - if (err && !ret) { - ret = ECGOTHER; - last_errno = errno; - } - mount = mount->next; - } - return ret; -} - -int cgroup_config_unload_config(const char *pathname, int flags) -{ - int ret, i, error; - int namespace_enabled = 0; - int mount_enabled = 0; - - cgroup_dbg("cgroup_config_unload_config: parsing %s\n", pathname); - ret = cgroup_parse_config(pathname); - if (ret) - goto err; - - namespace_enabled = (config_namespace_table[0].name[0] != '\0'); - mount_enabled = (config_mount_table[0].name[0] != '\0'); - /* - * The configuration should have namespace or mount, not both. - */ - if (namespace_enabled && mount_enabled) { - free(config_cgroup_table); - return ECGMOUNTNAMESPACE; - } - - ret = config_order_namespace_table(); - if (ret) - goto err; - - ret = config_validate_namespaces(); - if (ret) - goto err; - - /* - * Delete the groups in reverse order, i.e. subgroups first, then - * parents. - */ - cgroup_config_sort_groups(); - for (i = cgroup_table_index-1; i >= 0; i--) { - struct cgroup *cgroup = &config_cgroup_table[i]; - cgroup_dbg("removing %s\n", pathname); - error = cgroup_delete_cgroup_ext(cgroup, flags); - if (error && !ret) { - /* store the error, but continue deleting the rest */ - ret = error; - } - } - - /* Delete templates */ - for (i = 0; i < config_template_table_index; i++) { - struct cgroup *cgroup = &config_template_table[i]; - cgroup_dbg("removing %s\n", pathname); - error = cgroup_delete_cgroup_ext(cgroup, flags); - if (error && !ret) { - /* store the error, but continue deleting the rest */ - ret = error; - } - } - config_template_table_index = 0; - - if (mount_enabled) { - for (i = 0; i < config_table_index; i++) { - struct cg_mount_table_s *m = &(config_mount_table[i]); - cgroup_dbg("unmounting %s\n", m->name); - error = cgroup_config_try_unmount(m); - if (error && !ret) - ret = error; - } - } - -err: - cgroup_free_config(); - return ret; -} - -static int cgroup_config_unload_controller(const struct cgroup_mount_point *mount_info) -{ - int ret, error; - struct cgroup *cgroup = NULL; - struct cgroup_controller *cgc = NULL; - char path[FILENAME_MAX]; - void *handle; - - cgroup = cgroup_new_cgroup("."); - if (cgroup == NULL) - return ECGFAIL; - - cgc = cgroup_add_controller(cgroup, mount_info->name); - if (cgc == NULL) { - ret = ECGFAIL; - goto out_error; - } - - ret = cgroup_delete_cgroup_ext(cgroup, CGFLAG_DELETE_RECURSIVE); - if (ret != 0) - goto out_error; - - /* unmount everything */ - ret = cgroup_get_subsys_mount_point_begin(mount_info->name, &handle, - path); - while (ret == 0) { - error = umount(path); - if (error) { - cgroup_warn("Warning: cannot unmount controller %s on %s: %s\n", - mount_info->name, path, - strerror(errno)); - last_errno = errno; - ret = ECGOTHER; - goto out_error; - } - ret = cgroup_get_subsys_mount_point_next(&handle, path); - } - cgroup_get_subsys_mount_point_end(&handle); - if (ret == ECGEOF) - ret = 0; -out_error: - if (cgroup) - cgroup_free(&cgroup); - return ret; -} - -int cgroup_unload_cgroups(void) -{ - int error = 0; - void *ctrl_handle = NULL; - int ret = 0; - char *curr_path = NULL; - struct cgroup_mount_point info; - - error = cgroup_init(); - - if (error) { - ret = error; - goto out_error; - } - - error = cgroup_get_controller_begin(&ctrl_handle, &info); - while (error == 0) { - if (!curr_path || strcmp(info.path, curr_path) != 0) { - if (curr_path) - free(curr_path); - - curr_path = strdup(info.path); - if (!curr_path) - goto out_errno; - - error = cgroup_config_unload_controller(&info); - if (error) { - /* remember the error and continue unloading - * the rest */ - cgroup_warn("Warning: cannot clear controller %s\n", - info.name); - ret = error; - error = 0; - } - } - - error = cgroup_get_controller_next(&ctrl_handle, &info); - } - if (error == ECGEOF) - error = 0; - if (error) - ret = error; -out_error: - if (curr_path) - free(curr_path); - cgroup_get_controller_end(&ctrl_handle); - return ret; - -out_errno: - last_errno = errno; - cgroup_get_controller_end(&ctrl_handle); - return ECGOTHER; -} - -/** - * Defines the default group. The parser puts content of 'default { }' to - * topmost group in config_cgroup_table. This function copies the permissions - * from it to our default cgroup. - */ -int cgroup_config_define_default(void) -{ - struct cgroup *config_cgroup = - &config_cgroup_table[cgroup_table_index]; - - init_cgroup_table(&default_group, 1); - if (config_cgroup->control_dperm != NO_PERMS) - default_group.control_dperm = config_cgroup->control_dperm; - if (config_cgroup->control_fperm != NO_PERMS) - default_group.control_fperm = config_cgroup->control_fperm; - if (config_cgroup->control_gid != NO_UID_GID) - default_group.control_gid = config_cgroup->control_gid; - if (config_cgroup->control_uid != NO_UID_GID) - default_group.control_uid = config_cgroup->control_uid; - if (config_cgroup->task_fperm != NO_PERMS) - default_group.task_fperm = config_cgroup->task_fperm; - if (config_cgroup->tasks_gid != NO_UID_GID) - default_group.tasks_gid = config_cgroup->tasks_gid; - if (config_cgroup->tasks_uid != NO_UID_GID) - default_group.tasks_uid = config_cgroup->tasks_uid; - - /* - * Reset all changes made by 'default { }' to the topmost group so it - * can be used by following 'group { }'. - */ - init_cgroup_table(config_cgroup, 1); - return 0; -} - -int cgroup_config_set_default(struct cgroup *new_default) -{ - if (!new_default) - return ECGINVAL; - - init_cgroup_table(&default_group, 1); - - default_group.control_dperm = new_default->control_dperm; - default_group.control_fperm = new_default->control_fperm; - default_group.control_gid = new_default->control_gid; - default_group.control_uid = new_default->control_uid; - default_group.task_fperm = new_default->task_fperm; - default_group.tasks_gid = new_default->tasks_gid; - default_group.tasks_uid = new_default->tasks_uid; - default_group_set = 1; - - return 0; -} - -/** - * Reloads the templates list, using the given configuration file. - * @return 0 on success, > 0 on failure - */ -int cgroup_reload_cached_templates(char *pathname) -{ - int i; - int ret = 0; - - if (template_table) { - /* template structures have to be free */ - for (i = 0; i < template_table_index; i++) - cgroup_free_controllers(&template_table[i]); - free(template_table); - template_table = NULL; - } - template_table_index = 0; - - if ((config_template_table_index != 0) || (config_table_index != 0)) { - /* config template structures have to be free as well*/ - cgroup_free_config(); - } - - /* reloading data to config template structures */ - cgroup_dbg("Reloading cached templates from %s.\n", pathname); - ret = cgroup_parse_config(pathname); - if (ret) { - cgroup_dbg("Could not reload template cache, error was: %d\n", - ret); - return ret; - } - - /* copy data to templates cache structures */ - template_table_index = config_template_table_index; - template_table = calloc(template_table_index, sizeof(struct cgroup)); - if (template_table == NULL) { - ret = ECGOTHER; - return ret; - } - - for (i = 0; i < template_table_index; i++) { - cgroup_copy_cgroup(&template_table[i], - &config_template_table[i]); - strcpy((template_table[i]).name, - (config_template_table[i]).name); - template_table[i].tasks_uid = - config_template_table[i].tasks_uid; - template_table[i].tasks_gid = - config_template_table[i].tasks_gid; - template_table[i].task_fperm = - config_template_table[i].task_fperm; - template_table[i].control_uid = - config_template_table[i].control_uid; - template_table[i].control_gid = - config_template_table[i].control_gid; - template_table[i].control_fperm = - config_template_table[i].control_fperm; - template_table[i].control_dperm = - config_template_table[i].control_dperm; - } - - return ret; -} - -/** - * Initializes the templates cache. - * @return 0 on success, > 0 on error - */ -int cgroup_init_templates_cache(char *pathname) -{ - int ret = 0; - int i; - - if (template_table) { - /* template structures have to be free */ - for (i = 0; i < template_table_index; i++) - cgroup_free_controllers(&template_table[i]); - free(template_table); - template_table = NULL; - } - template_table_index = 0; - - if ((config_template_table_index != 0) || (config_table_index != 0)) { - /* config structures have to be clean */ - cgroup_free_config(); - } - - cgroup_dbg("Loading cached templates from %s.\n", pathname); - /* Attempt to read the configuration file and cache the rules. */ - ret = cgroup_parse_config(pathname); - if (ret) { - cgroup_dbg("Could not initialize rule cache, error was: %d\n", - ret); - return ret; - } - - /* copy template data to templates cache structures */ - template_table_index = config_template_table_index; - template_table = calloc(template_table_index, sizeof(struct cgroup)); - if (template_table == NULL) { - ret = ECGOTHER; - return ret; - } - - for (i = 0; i < template_table_index; i++) { - cgroup_copy_cgroup(&template_table[i], - &config_template_table[i]); - strcpy((template_table[i]).name, - (config_template_table[i]).name); - template_table[i].tasks_uid = - config_template_table[i].tasks_uid; - template_table[i].tasks_gid = - config_template_table[i].tasks_gid; - template_table[i].task_fperm = - config_template_table[i].task_fperm; - template_table[i].control_uid = - config_template_table[i].control_uid; - template_table[i].control_gid = - config_template_table[i].control_gid; - template_table[i].control_fperm = - config_template_table[i].control_fperm; - template_table[i].control_dperm = - config_template_table[i].control_dperm; - } - - return ret; - - -} - -/** - * Setting source files of templates. This function has to be called before - * any call of cgroup_load_templates_cache_from_files. - * @param tmpl_files - */ -void cgroup_templates_cache_set_source_files( - struct cgroup_string_list *tmpl_files) -{ - template_files = tmpl_files; -} - -/** - * Appending cgroup templates parsed by parser to template_table - * @param offset number of templates already in the table - */ -int cgroup_add_cgroup_templates(int offset) -{ - int i, ti, ret; - - for (i = 0; i < config_template_table_index; i++) { - ti = i + offset; - ret = cgroup_copy_cgroup(&template_table[ti], - &config_template_table[i]); - if (ret) - return ret; - - strcpy((template_table[ti]).name, - (config_template_table[i]).name); - template_table[ti].tasks_uid = - config_template_table[i].tasks_uid; - template_table[ti].tasks_gid = - config_template_table[i].tasks_gid; - template_table[ti].task_fperm = - config_template_table[i].task_fperm; - template_table[ti].control_uid = - config_template_table[i].control_uid; - template_table[ti].control_gid = - config_template_table[i].control_gid; - template_table[ti].control_fperm = - config_template_table[i].control_fperm; - template_table[ti].control_dperm = - config_template_table[i].control_dperm; - } - - return 0; -} - -/** - * Expand template table based on new number of parsed templates, i.e. - * on value of config_template_table_index. - * Change value of template_table_index. - * @return 0 on success, < 0 on error - */ -int cgroup_expand_template_table(void) -{ - int i; - - template_table = realloc(template_table, - (template_table_index + config_template_table_index) - *sizeof(struct cgroup)); - - if (template_table == NULL) - return -ECGOTHER; - - for (i = 0; i < config_template_table_index; i++) - template_table[i + template_table_index].index = 0; - - template_table_index += config_template_table_index; - - return 0; -} - -/** - * Load the templates cache from files. Before calling this function, - * cgroup_templates_cache_set_source_files has to be called first. - * @param file_index index of file which was unable to be parsed - * @return 0 on success, > 0 on error - */ -int cgroup_load_templates_cache_from_files(int *file_index) -{ - int ret; - int i, j; - int template_table_last_index; - char *pathname; - - if (!template_files) { - /* source files has not been set */ - cgroup_dbg("Template source files have not been set. "); - cgroup_dbg("Using only %s\n", CGCONFIG_CONF_FILE); - - if (template_table_index == 0) - /* the rules cache is empty */ - return cgroup_init_templates_cache( - CGCONFIG_CONF_FILE); - else - /* cache is not empty */ - return cgroup_reload_cached_templates( - CGCONFIG_CONF_FILE); - } - - if (template_table) { - /* template structures have to be free */ - for (i = 0; i < template_table_index; i++) - cgroup_free_controllers(&template_table[i]); - free(template_table); - template_table = NULL; - } - template_table_index = 0; - - if ((config_template_table_index != 0) || (config_table_index != 0)) { - /* config structures have to be clean before parsing */ - cgroup_free_config(); - } - - for (j = 0; j < template_files->count; j++) { - pathname = template_files->items[j]; - - cgroup_dbg("Parsing templates from %s.\n", pathname); - /* Attempt to read the configuration file - * and cache the rules. */ - ret = cgroup_parse_config(pathname); - if (ret) { - cgroup_dbg("Could not initialize rule cache, "); - cgroup_dbg("error was: %d\n", ret); - *file_index = j; - return ret; - } - - if (config_template_table_index > 0) { - template_table_last_index = template_table_index; - ret = cgroup_expand_template_table(); - if (ret) { - cgroup_dbg("Could not expand template table, "); - cgroup_dbg("error was: %d\n", -ret); - *file_index = j; - return -ret; - } - - /* copy template data to templates cache structures */ - cgroup_dbg("Copying templates to template table "); - cgroup_dbg("from %s.\n", pathname); - ret = cgroup_add_cgroup_templates( - template_table_last_index); - if (ret) { - cgroup_dbg("Unable to copy cgroup\n"); - *file_index = j; - return ret; - } - cgroup_dbg("Templates to template table copied\n"); - } - } - - return 0; -} - -/* - * Create a given cgroup, based on template configuration if it is present - * if the template is not present cgroup is creted using cgroup_create_cgroup - */ -int cgroup_config_create_template_group(struct cgroup *cgroup, - char *template_name, int flags) -{ - int ret = 0; - int i, j, k; - struct cgroup *t_cgroup; - char buffer[FILENAME_MAX]; - struct cgroup *aux_cgroup = NULL; - struct cgroup_controller *cgc; - int found; - - /* - * If the user did not ask for cached rules, we must parse the - * configuration file and prepare template structures now. We - * use CGCONFIG_CONF_FILE by default - */ - if (!(flags & CGFLAG_USE_TEMPLATE_CACHE)) { - int fileindex; - - /* the rules cache is empty */ - ret = cgroup_load_templates_cache_from_files( - &fileindex); - if (ret != 0) { - if (fileindex < 0) { - cgroup_dbg("Error: Template source files "); - cgroup_dbg("have not been set\n"); - } else { - cgroup_dbg("Error: Failed to load template"); - cgroup_dbg("rules from %s. ", - template_files->items[fileindex]); - } - } - - if (ret != 0) { - cgroup_dbg("Failed initialize templates cache.\n"); - return ret; - } - } - - for (i = 0; cgroup->controller[i] != NULL; i++) { - /* for each controller we have to add to cgroup structure - * either template cgroup or empty controller */ - - found = 0; - /* look for relevant template - test name x controller pair */ - for (j = 0; j < template_table_index; j++) { - - t_cgroup = &template_table[j]; - if (strcmp(t_cgroup->name, template_name) != 0) { - /* template name does not match skip template */ - continue; - } - - /* template name match */ - for (k = 0; t_cgroup->controller[k] != NULL; k++) { - if (strcmp((cgroup->controller[i])->name, - (t_cgroup->controller[k])->name) != 0) { - /* controller name does not match */ - continue; - } - - /* name and controller match template found */ - /* variables substituted in template */ - strncpy(buffer, t_cgroup->name, - FILENAME_MAX-1); - strncpy(t_cgroup->name, cgroup->name, - FILENAME_MAX-1); - - ret = cgroup_create_cgroup(t_cgroup, flags); - - strncpy(t_cgroup->name, buffer, - FILENAME_MAX-1); - if (ret) { - cgroup_dbg("creating group %s, error %d\n", - cgroup->name, ret); - goto end; - } else { - /* go to new controller */ - j = template_table_index; - found = 1; - continue; - } - - } - } - - if (found == 1) - continue; - - /* no template is present for given name x controller pair - * add controller to result cgroup */ - aux_cgroup = cgroup_new_cgroup(cgroup->name); - if (!aux_cgroup) { - ret = ECGINVAL; - fprintf(stderr, "cgroup %s can't be created\n", - cgroup->name); - goto end; - } - cgc = cgroup_add_controller(aux_cgroup, - (cgroup->controller[i])->name); - if (cgc == NULL) { - ret = ECGINVAL; - fprintf(stderr, "cgroup %s can't be created\n", - cgroup->name); - goto end; - } - ret = cgroup_create_cgroup(aux_cgroup, flags); - if (ret) { - ret = ECGINVAL; - fprintf(stderr, "cgroup %s can't be created\n", - cgroup->name); - goto end; - } - } - -end: - cgroup_free(&aux_cgroup); - return ret; -} diff --git a/src/daemon/.gitignore b/src/daemon/.gitignore deleted file mode 100644 index b3855c42..00000000 --- a/src/daemon/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cgrulesengd diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am deleted file mode 100644 index abbbe300..00000000 --- a/src/daemon/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/include - -if WITH_DAEMON - -sbin_PROGRAMS = cgrulesengd -cgrulesengd_SOURCES = cgrulesengd.c cgrulesengd.h ../tools/tools-common.h ../tools/tools-common.c -cgrulesengd_LDADD = $(top_builddir)/src/.libs/libcgroup.la -lrt -cgrulesengd_LDFLAGS = -L$(top_builddir)/src/.libs - -endif diff --git a/src/daemon/cgrulesengd.c b/src/daemon/cgrulesengd.c deleted file mode 100644 index 4cef53ee..00000000 --- a/src/daemon/cgrulesengd.c +++ /dev/null @@ -1,1306 +0,0 @@ -/* - * Copyright Red Hat Inc. 2008 - * - * Author: Steve Olivieri - * Author: Vivek Goyal - * - * Some part of the programs have been derived from Dhaval Giani's posting - * for daemon to place the task in right container. Original copyright notice - * follows. - * - * Copyright IBM Corporation, 2007 - * Author: Dhaval Giani linux.vnet.ibm.com> - * Derived from test_cn_proc.c by Matt Helsley - * Original copyright notice follows - * - * Copyright (C) Matt Helsley, IBM Corp. 2005 - * Derived from fcctl.c by Guillaume Thouvenin - * Original copyright notice follows: - * - * Copyright (C) 2005 BULL SA. - * Written by Guillaume Thouvenin bull.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * TODO Stop using netlink for communication (or at least rewrite that part). - */ - -#include "libcgroup.h" -#include "cgrulesengd.h" -#include "../libcgroup-internal.h" -#include "../tools/tools-common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define NUM_PER_REALLOCATIOM (100) - -/* list of config files from CGCONFIG_CONF_FILE and CGCONFIG_CONF_DIR */ -static struct cgroup_string_list template_files; - -/* Log file, NULL if logging to file is disabled */ -FILE* logfile; - -/* Log facility, 0 if logging to syslog is disabled */ -int logfacility; - -/* Current log level */ -int loglevel; - -/* Owner of the socket, -1 means no change */ -uid_t socket_user = -1; - -/* Owner of the socket, -1 means no change */ -gid_t socket_group = -1; - -/** - * Prints the usage information for this program and, optionally, an error - * message. This function uses vfprintf. - * @param fd The file stream to print to - * @param msg The error message to print (printf style) - * @param ... Any args to msg (printf style) - */ -static void usage(FILE* fd, const char* msg, ...) -{ - /* List of args to msg */ - va_list ap; - - /* Put all args after msg into the list. */ - va_start(ap, msg); - - if (msg) - vfprintf(fd, msg, ap); - fprintf(fd, "\n"); - fprintf(fd, "cgrulesengd -- a daemon for the cgroups rules engine\n\n"); - fprintf(fd, "Usage : cgrulesengd [options]\n\n"); - fprintf(fd, " options :\n"); - fprintf(fd, " -q | --quiet quiet mode\n" - " -v | --verbose verbose mode\n" - " -f | --logfile= write log to file\n" - " -s[facility] | --syslog=[facility] write log to syslog\n" - " -n | --nodaemom don't fork daemon\n" - " -d | --debug same as -v -v -n -f -\n" - " -Q | --nolog disable logging\n" - " -u | --socket-user= set " - CGRULE_CGRED_SOCKET_PATH " socket user\n" - " -g | --socket-group= set " - CGRULE_CGRED_SOCKET_PATH " socket group\n" - " -h | --help show this help\n\n" - ); - va_end(ap); -} - -/** - * Prints a formatted message (like vprintf()) to all log destinations. - * Flushes the file stream's buffer so that the message is immediately - * readable. - * @param level The log level (LOG_EMERG ... LOG_DEBUG) - * @param format The format for the message (vprintf style) - * @param ap Any args to format (vprintf style) - */ -void flog_write(int level, const char *format, va_list ap) -{ - va_list cap; - int copy = 0; - - /* Check the log level */ - if (level > loglevel) - return; - - /* copy the argument list if needed - it can be processed only once */ - if (logfile && logfacility) { - copy = 1; - va_copy(cap, ap); - } - - if (logfile) { - /* Print the message to the given stream. */ - vfprintf(logfile, format, ap); - - /* - * Flush the stream's buffer, so the data is readable - * immediately. - */ - fflush(logfile); - } - - if (logfacility) { - if (copy) { - vsyslog(LOG_MAKEPRI(logfacility, level), format, cap); - va_end(cap); - } else - vsyslog(LOG_MAKEPRI(logfacility, level), format, ap); - } -} - -/** - * Prints a formatted message (like printf()) to all log destinations. - * Flushes the file stream's buffer so that the message is immediately - * readable. - * @param level The log level (LOG_EMERG ... LOG_DEBUG) - * @param format The format for the message (printf style) - * @param ... Any args to format (printf style) - */ -void flog(int level, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - flog_write(level, format, ap); - va_end(ap); -} - -/** - * Libcgroup logging callback. It must translate libcgroup log levels to - * cgrulesengd native (=syslog). - */ -void flog_cgroup(void *userdata, int cgroup_level, const char *format, - va_list ap) -{ - int level = 0; - switch (cgroup_level) { - case CGROUP_LOG_ERROR: - level = LOG_ERR; - break; - case CGROUP_LOG_WARNING: - level = LOG_WARNING; - break; - case CGROUP_LOG_INFO: - level = LOG_INFO; - break; - case CGROUP_LOG_DEBUG: - level = LOG_DEBUG; - break; - } - flog_write(level, format, ap); -} - -struct parent_info { - __u64 timestamp; - pid_t pid; -}; -struct array_parent_info { - int index; - int num_allocation; - struct parent_info **parent_info; -}; -struct array_parent_info array_pi; - -static int cgre_store_parent_info(pid_t pid) -{ - __u64 uptime_ns; - struct timespec tp; - struct parent_info *info; - - if (clock_gettime(CLOCK_MONOTONIC, &tp) < 0) { - flog(LOG_WARNING, "Failed to get time\n"); - return 1; - } - uptime_ns = ((__u64)tp.tv_sec * 1000 * 1000 * 1000 ) + tp.tv_nsec; - - if (array_pi.index >= array_pi.num_allocation) { - int alloc = array_pi.num_allocation + NUM_PER_REALLOCATIOM; - void *new_array = realloc(array_pi.parent_info, - sizeof(info) * alloc); - if (!new_array) { - flog(LOG_WARNING, "Failed to allocate memory\n"); - return 1; - } - array_pi.parent_info = new_array; - array_pi.num_allocation = alloc; - } - info = calloc(1, sizeof(struct parent_info)); - if (!info) { - flog(LOG_WARNING, "Failed to allocate memory\n"); - return 1; - } - info->timestamp = uptime_ns; - info->pid = pid; - - array_pi.parent_info[array_pi.index] = info; - array_pi.index++; - - return 0; -} - -static void cgre_remove_old_parent_info(__u64 key_timestamp) -{ - int i, j; - - for (i = 0; i < array_pi.index; i++) { - if (key_timestamp < array_pi.parent_info[i]->timestamp) - continue; - free(array_pi.parent_info[i]); - for (j = i; j < array_pi.index - 1; j++) - array_pi.parent_info[j] = array_pi.parent_info[j + 1]; - array_pi.index--; - i--; - } - return; -} - -static int cgre_was_parent_changed_when_forking(const struct proc_event *ev) -{ - int i; - pid_t parent_pid; - __u64 timestamp_child; - __u64 timestamp_parent; - - parent_pid = ev->event_data.fork.parent_pid; - timestamp_child = ev->timestamp_ns; - - cgre_remove_old_parent_info(timestamp_child); - - for (i = 0; i < array_pi.index; i++) { - if (parent_pid != array_pi.parent_info[i]->pid) - continue; - timestamp_parent = array_pi.parent_info[i]->timestamp; - if (timestamp_child > timestamp_parent) - continue; - return 1; - } - return 0; -} - -struct unchanged_pid { - pid_t pid; - int flags; -} unchanged_pid_t; - -struct array_unchanged { - int index; - int num_allocation; - struct unchanged_pid *proc; -}; - -struct array_unchanged array_unch; - -static int cgre_store_unchanged_process(pid_t pid, int flags) -{ - int i; - - for (i = 0; i < array_unch.index; i++) { - if (array_unch.proc[i].pid != pid) - continue; - /* pid is stored already. */ - return 0; - } - if (array_unch.index >= array_unch.num_allocation) { - int alloc = array_unch.num_allocation + NUM_PER_REALLOCATIOM; - void *new_array = realloc(array_unch.proc, - sizeof(unchanged_pid_t) * alloc); - if (!new_array) { - flog(LOG_WARNING, "Failed to allocate memory\n"); - return 1; - } - array_unch.proc = new_array; - array_unch.num_allocation = alloc; - } - array_unch.proc[array_unch.index].pid = pid; - array_unch.proc[array_unch.index].flags = flags; - array_unch.index++; - flog(LOG_DEBUG, "Store the unchanged process (PID: %d, FLAGS: %d)\n", - pid, flags); - return 0; -} - -static void cgre_remove_unchanged_process(pid_t pid) -{ - int i, j; - - for (i = 0; i < array_unch.index; i++) { - if (array_unch.proc[i].pid != pid) - continue; - for (j = i; j < array_unch.index - 1; j++) - memcpy(&array_unch.proc[j], - &array_unch.proc[j + 1], - sizeof(struct unchanged_pid)); - array_unch.index--; - flog(LOG_DEBUG, "Remove the unchanged process (PID: %d)\n", - pid); - break; - } - return; -} - -static int cgre_is_unchanged_process(pid_t pid) -{ - int i; - - for (i = 0; i < array_unch.index; i++) { - if (array_unch.proc[i].pid != pid) - continue; - return 1; - } - return 0; -} - -static int cgre_is_unchanged_child(pid_t pid) -{ - int i; - - for (i = 0; i < array_unch.index; i++) { - if (array_unch.proc[i].pid != pid) - continue; - if (array_unch.proc[i].flags & CGROUP_DAEMON_UNCHANGE_CHILDREN) - return 1; - break; - } - return 0; -} - -/** - * Process an event from the kernel, and determine the correct UID/GID/PID to - * pass to libcgroup. Then, libcgroup will decide the cgroup to move the PID - * to, if any. - * @param ev The event to process - * @param type The type of event to process (part of ev) - * @return 0 on success, > 0 on failure - */ -int cgre_process_event(const struct proc_event *ev, const int type) -{ - char *procname; - pid_t ppid, cpid; - pid_t pid = 0, log_pid = 0; - uid_t euid, log_uid = 0; - gid_t egid, log_gid = 0; - - int ret = 0; - - switch (type) { - case PROC_EVENT_UID: - case PROC_EVENT_GID: - /* - * If the unchanged process, the daemon should not change the - * cgroup of the process. - */ - if (cgre_is_unchanged_process(ev->event_data.id.process_pid)) - return 0; - pid = ev->event_data.id.process_pid; - break; - case PROC_EVENT_FORK: - ppid = ev->event_data.fork.parent_pid; - cpid = ev->event_data.fork.child_pid; - if (cgre_is_unchanged_child(ppid)) { - if (cgre_store_unchanged_process(cpid, - CGROUP_DAEMON_UNCHANGE_CHILDREN)) - return 1; - } - - /* - * If this process was forked while changing parent's cgroup, - * this process's cgroup also should be changed. - */ - if (!cgre_was_parent_changed_when_forking(ev)) - return 0; - pid = ev->event_data.fork.child_pid; - break; - case PROC_EVENT_EXIT: - cgre_remove_unchanged_process(ev->event_data.exit.process_pid); - return 0; - case PROC_EVENT_EXEC: - /* - * If the unchanged process, the daemon should not change the - * cgroup of the process. - */ - if (cgre_is_unchanged_process(ev->event_data.exec.process_pid)) - return 0; - pid = ev->event_data.exec.process_pid; - break; - default: - break; - } - ret = cgroup_get_uid_gid_from_procfs(pid, &euid, &egid); - if (ret == ECGROUPNOTEXIST) - /* cgroup_get_uid_gid_from_procfs() returns ECGROUPNOTEXIST - * if a process finished and that is not a problem. */ - return 0; - else if (ret) - return ret; - - ret = cgroup_get_procname_from_procfs(pid, &procname); - if (ret == ECGROUPNOTEXIST) - return 0; - else if (ret) - return ret; - - /* - * Now that we have the UID, the GID, and the PID, we can make a call - * to libcgroup to change the cgroup for this PID. - */ - log_pid = pid; - switch (type) { - case PROC_EVENT_UID: - log_uid = ev->event_data.id.e.euid; - log_gid = egid; - euid = ev->event_data.id.e.euid; - break; - case PROC_EVENT_GID: - log_uid = euid; - log_gid = ev->event_data.id.e.egid; - egid = ev->event_data.id.e.egid; - break; - case PROC_EVENT_FORK: - log_uid = euid; - log_gid = egid; - break; - case PROC_EVENT_EXEC: - log_uid = euid; - log_gid = egid; - break; - default: - break; - } - ret = cgroup_change_cgroup_flags(euid, egid, procname, pid, - CGFLAG_USECACHE); - if (ret == ECGOTHER) { - /* A process finished already but we may have missed changing it, - * make sure to apply to forked children. */ - if (cgroup_get_last_errno() == ESRCH || cgroup_get_last_errno() == ENOENT) - ret = cgre_store_parent_info(pid); - else - ret = 0; - } else if (ret) { - flog(LOG_WARNING, - "Cgroup change for PID: %d, UID: %d, GID: %d, PROCNAME: %s FAILED! (Error Code: %d)\n", - log_pid, log_uid, log_gid, procname, ret); - } else { - flog(LOG_INFO, - "Cgroup change for PID: %d, UID: %d, GID: %d, PROCNAME: %s OK\n", - log_pid, log_uid, log_gid, procname); - ret = cgre_store_parent_info(pid); - } - free(procname); - return ret; -} - -/** - * Handle a netlink message. In the event of PROC_EVENT_UID or PROC_EVENT_GID, - * we pass the event along to cgre_process_event for further processing. All - * other events are ignored. - * @param cn_hdr The netlink message - * @return 0 on success, > 0 on error - */ -static int cgre_handle_msg(struct cn_msg *cn_hdr) -{ - /* The event to consider */ - struct proc_event *ev; - - /* Return codes */ - int ret = 0; - - /* Get the event data. We only care about two event types. */ - ev = (struct proc_event*)cn_hdr->data; - switch (ev->what) { - case PROC_EVENT_UID: - flog(LOG_DEBUG, - "UID Event: PID = %d, tGID = %d, rUID = %d, eUID = %d\n", - ev->event_data.id.process_pid, - ev->event_data.id.process_tgid, - ev->event_data.id.r.ruid, - ev->event_data.id.e.euid); - ret = cgre_process_event(ev, PROC_EVENT_UID); - break; - case PROC_EVENT_GID: - flog(LOG_DEBUG, - "GID Event: PID = %d, tGID = %d, rGID = %d, eGID = %d\n", - ev->event_data.id.process_pid, - ev->event_data.id.process_tgid, - ev->event_data.id.r.rgid, - ev->event_data.id.e.egid); - ret = cgre_process_event(ev, PROC_EVENT_GID); - break; - case PROC_EVENT_FORK: - ret = cgre_process_event(ev, PROC_EVENT_FORK); - break; - case PROC_EVENT_EXIT: - ret = cgre_process_event(ev, PROC_EVENT_EXIT); - break; - case PROC_EVENT_EXEC: - flog(LOG_DEBUG, "EXEC Event: PID = %d, tGID = %d\n", - ev->event_data.exec.process_pid, - ev->event_data.exec.process_tgid); - ret = cgre_process_event(ev, PROC_EVENT_EXEC); - break; - default: - break; - } - - return ret; -} - -static int cgre_receive_netlink_msg(int sk_nl) -{ - char buff[BUFF_SIZE]; - size_t recv_len; - struct sockaddr_nl from_nla; - socklen_t from_nla_len; - struct nlmsghdr *nlh; - struct cn_msg *cn_hdr; - - memset(buff, 0, sizeof(buff)); - from_nla_len = sizeof(from_nla); - recv_len = recvfrom(sk_nl, buff, sizeof(buff), 0, - (struct sockaddr *)&from_nla, &from_nla_len); - if (recv_len == ENOBUFS) { - flog(LOG_ERR, "ERROR: NETLINK BUFFER FULL, MESSAGE DROPPED!\n"); - return 0; - } - if (recv_len < 1) - return 0; - - if (from_nla_len != sizeof(from_nla)) { - flog(LOG_ERR, "Bad address size reading netlink socket\n"); - return 0; - } - if (from_nla.nl_groups != CN_IDX_PROC - || from_nla.nl_pid != 0) - return 0; - - nlh = (struct nlmsghdr *)buff; - while (NLMSG_OK(nlh, recv_len)) { - cn_hdr = NLMSG_DATA(nlh); - if (nlh->nlmsg_type == NLMSG_NOOP) { - nlh = NLMSG_NEXT(nlh, recv_len); - continue; - } - if ((nlh->nlmsg_type == NLMSG_ERROR) || - (nlh->nlmsg_type == NLMSG_OVERRUN)) - break; - if (cgre_handle_msg(cn_hdr) < 0) - return 1; - if (nlh->nlmsg_type == NLMSG_DONE) - break; - nlh = NLMSG_NEXT(nlh, recv_len); - } - return 0; -} - -static void cgre_receive_unix_domain_msg(int sk_unix) -{ - int flags; - int fd_client; - pid_t pid; - struct sockaddr_un caddr; - socklen_t caddr_len; - struct stat buff_stat; - char path[FILENAME_MAX]; - - caddr_len = sizeof(caddr); - fd_client = accept(sk_unix, (struct sockaddr *)&caddr, &caddr_len); - if (fd_client < 0) { - flog(LOG_WARNING, "Warning: 'accept' command error: %s\n", - strerror(errno)); - return; - } - if (read(fd_client, &pid, sizeof(pid)) < 0) { - flog(LOG_WARNING, "Warning: 'read' command error: %s\n", - strerror(errno)); - goto close; - } - sprintf(path, "/proc/%d", pid); - if (stat(path, &buff_stat)) { - flog(LOG_WARNING, - "Warning: there is no such process (PID: %d)\n", - pid); - goto close; - } - if (read(fd_client, &flags, sizeof(flags)) < 0) { - flog(LOG_WARNING, "Warning: error reading daemon socket: %s\n", - strerror(errno)); - goto close; - } - if (flags == CGROUP_DAEMON_CANCEL_UNCHANGE_PROCESS) { - cgre_remove_unchanged_process(pid); - } else { - if (cgre_store_unchanged_process(pid, flags)) - goto close; - } - if (write(fd_client, CGRULE_SUCCESS_STORE_PID, - sizeof(CGRULE_SUCCESS_STORE_PID)) < 0) { - flog(LOG_WARNING, - "Warning: cannot write to daemon socket: %s\n", - strerror(errno)); - goto close; - } -close: - close(fd_client); - return; -} - -static int cgre_create_netlink_socket_process_msg(void) -{ - int sk_nl = 0, sk_unix = 0, sk_max; - struct sockaddr_nl my_nla; - char buff[BUFF_SIZE]; - int rc = -1; - struct nlmsghdr *nl_hdr; - struct cn_msg *cn_hdr; - enum proc_cn_mcast_op *mcop_msg; - struct sockaddr_un saddr; - fd_set fds, readfds; - sigset_t sigset; - - /* - * Create an endpoint for communication. Use the kernel user - * interface device (PF_NETLINK) which is a datagram oriented - * service (SOCK_DGRAM). The protocol used is the connector - * protocol (NETLINK_CONNECTOR) - */ - sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); - if (sk_nl == -1) { - flog(LOG_ERR, "Error: error opening netlink socket: %s\n", - strerror(errno)); - return rc; - } - - my_nla.nl_family = AF_NETLINK; - my_nla.nl_groups = CN_IDX_PROC; - my_nla.nl_pid = getpid(); - my_nla.nl_pad = 0; - - if (bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla)) < 0) { - flog(LOG_ERR, "Error: error binding netlink socket: %s\n", - strerror(errno)); - goto close_and_exit; - } - - nl_hdr = (struct nlmsghdr *)buff; - cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr); - mcop_msg = (enum proc_cn_mcast_op*)&cn_hdr->data[0]; - flog(LOG_DEBUG, "Sending proc connector: PROC_CN_MCAST_LISTEN...\n"); - memset(buff, 0, sizeof(buff)); - *mcop_msg = PROC_CN_MCAST_LISTEN; - - /* fill the netlink header */ - nl_hdr->nlmsg_len = SEND_MESSAGE_LEN; - nl_hdr->nlmsg_type = NLMSG_DONE; - nl_hdr->nlmsg_flags = 0; - nl_hdr->nlmsg_seq = 0; - nl_hdr->nlmsg_pid = getpid(); - - /* fill the connector header */ - cn_hdr->id.idx = CN_IDX_PROC; - cn_hdr->id.val = CN_VAL_PROC; - cn_hdr->seq = 0; - cn_hdr->ack = 0; - cn_hdr->len = sizeof(enum proc_cn_mcast_op); - flog(LOG_DEBUG, "Sending netlink message len=%d, cn_msg len=%d\n", - nl_hdr->nlmsg_len, (int) sizeof(struct cn_msg)); - if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) { - flog(LOG_ERR, - "Error: failed to send netlink message (mcast ctl op): %s\n", - strerror(errno)); - goto close_and_exit; - } - flog(LOG_DEBUG, "Message sent\n"); - - /* - * Setup Unix domain socket. - */ - sk_unix = socket(PF_UNIX, SOCK_STREAM, 0); - if (sk_unix < 0) { - flog(LOG_ERR, "Error creating UNIX socket: %s\n", - strerror(errno)); - goto close_and_exit; - } - memset(&saddr, 0, sizeof(saddr)); - saddr.sun_family = AF_UNIX; - strcpy(saddr.sun_path, CGRULE_CGRED_SOCKET_PATH); - unlink(CGRULE_CGRED_SOCKET_PATH); - if (bind(sk_unix, (struct sockaddr *)&saddr, - sizeof(saddr.sun_family) + strlen(CGRULE_CGRED_SOCKET_PATH)) < 0) { - flog(LOG_ERR, "Error binding UNIX socket %s: %s\n", - CGRULE_CGRED_SOCKET_PATH, strerror(errno)); - goto close_and_exit; - } - if (listen(sk_unix, 1) < 0) { - flog(LOG_ERR, "Error listening on UNIX socket %s: %s\n", - CGRULE_CGRED_SOCKET_PATH, strerror(errno)); - goto close_and_exit; - } - - /* change the owner */ - if (chown(CGRULE_CGRED_SOCKET_PATH, socket_user, socket_group) < 0) { - flog(LOG_ERR, "Error changing %s socket owner: %s\n", - CGRULE_CGRED_SOCKET_PATH, strerror(errno)); - goto close_and_exit; - } - flog(LOG_DEBUG, "Socket %s owner successfully set to %d:%d\n", - CGRULE_CGRED_SOCKET_PATH, (int) socket_user, - (int) socket_group); - - if (chmod(CGRULE_CGRED_SOCKET_PATH, 0660) < 0) { - flog(LOG_ERR, "Error changing %s socket permissions: %s\n", - CGRULE_CGRED_SOCKET_PATH, strerror(errno)); - goto close_and_exit; - } - - FD_ZERO(&readfds); - FD_SET(sk_nl, &readfds); - FD_SET(sk_unix, &readfds); - if (sk_nl < sk_unix) - sk_max = sk_unix; - else - sk_max = sk_nl; - - sigemptyset(&sigset); - sigaddset(&sigset, SIGUSR2); - for(;;) { - /* - * For avoiding the deadlock and "Interrupted system call" - * error, restrict the effective range of SIGUSR2 signal. - */ - sigprocmask(SIG_UNBLOCK, &sigset, NULL); - sigprocmask(SIG_BLOCK, &sigset, NULL); - - memcpy(&fds, &readfds, sizeof(fd_set)); - if (select(sk_max + 1, &fds, NULL, NULL, NULL) < 0) { - flog(LOG_ERR, "Selecting error: %s\n", strerror(errno)); - goto close_and_exit; - } - if (FD_ISSET(sk_nl, &fds)) { - if (cgre_receive_netlink_msg(sk_nl)) - break; - } - if (FD_ISSET(sk_unix, &fds)) - cgre_receive_unix_domain_msg(sk_unix); - } - -close_and_exit: - if (sk_nl >= 0) - close(sk_nl); - if (sk_unix >= 0) - close(sk_unix); - return rc; -} - -/** - * Start logging. Opens syslog and/or log file and sets log level. - * @param logp Path of the log file, NULL if no log file was specified - * @param logf Syslog facility, NULL if no facility was specified - * @param logv Log verbosity, 1 is the default, 0 = no logging, 4 = everything - */ -static void cgre_start_log(const char *logp, int logf, int logv) -{ - /* Current system time */ - time_t tm; - - /* Log levels */ - int loglevels[] = { - LOG_EMERG, /* -q */ - LOG_ERR, /* default */ - LOG_WARNING, /* -v */ - LOG_INFO, /* -vv */ - LOG_DEBUG /* -vvv */ - }; - - /* Set default logging destination if nothing was specified */ - if (!logp && !logf) - logf = LOG_DAEMON; - - /* Open log file */ - if (logp) { - if (strcmp("-", logp) == 0) { - logfile = stdout; - } else { - logfile = fopen(logp, "a"); - if (!logfile) { - fprintf(stderr, "Failed to open log file %s," - " error: %s. Continuing anyway.\n", - logp, strerror(errno)); - logfile = stdout; - } - } - } else - logfile = NULL; - - /* Open syslog */ - if (logf) { - openlog("CGRE", LOG_CONS | LOG_PID, logf); - logfacility = logf; - } else - logfacility = 0; - - /* Set the log level */ - if (logv < 0) - logv = 0; - if (logv >= sizeof(loglevels)/sizeof(int)) - logv = sizeof(loglevels)/sizeof(int)-1; - - loglevel = loglevels[logv]; - cgroup_set_logger(flog_cgroup, CGROUP_LOG_DEBUG, NULL); - - flog(LOG_DEBUG, "CGroup Rules Engine Daemon log started\n"); - tm = time(0); - flog(LOG_DEBUG, "Current time: %s\n", ctime(&tm)); - flog(LOG_DEBUG, "Opened log file: %s, log facility: %d,log level: %d\n", - logp, logfacility, loglevel); -} - - -/** - * Turns this program into a daemon. In doing so, we fork() and kill the - * parent process. Note too that stdout, stdin, and stderr are closed in - * daemon mode, and a file descriptor for a log file is opened. - * @param logp Path of the log file, NULL if no log file was specified - * @param logf Syslog facility, 0 if no facility was specified - * @param daemon False to turn off daemon mode (no fork, leave FDs open) - * @param logv Log verbosity, 1 is the default, 0 = no logging, 5 = everything - * @return 0 on success, > 0 on error - */ -int cgre_start_daemon(const char *logp, const int logf, - const unsigned char daemon, const int logv) -{ - /* PID returned from the fork() */ - pid_t pid; - - /* Fork and die. */ - if (daemon) { - pid = fork(); - if (pid < 0) { - openlog("CGRE", LOG_CONS, LOG_DAEMON|LOG_WARNING); - syslog(LOG_DAEMON|LOG_WARNING, "Failed to fork," - " error: %s", strerror(errno)); - closelog(); - fprintf(stderr, "Failed to fork(), %s\n", - strerror(errno)); - return 1; - } else if (pid > 0) { - exit(EXIT_SUCCESS); - } - } else { - flog(LOG_DEBUG, "Not using daemon mode\n"); - pid = getpid(); - } - - cgre_start_log(logp, logf, logv); - - if (!daemon) { - /* We can skip the rest, since we're not becoming a daemon. */ - flog(LOG_INFO, "Proceeding with PID %d\n", getpid()); - return 0; - } else { - /* Get a new SID for the child. */ - if (setsid() < 0) { - flog(LOG_ERR, "Failed to get a new SID, error: %s\n", - strerror(errno)); - return 2; - } - - /* Change to the root directory. */ - if (chdir("/") < 0) { - flog(LOG_ERR, "Failed to chdir to /, error: %s\n", - strerror(errno)); - return 3; - } - - /* Close standard file descriptors. */ - close(STDIN_FILENO); - if (logfile != stdout) - close(STDOUT_FILENO); - close(STDERR_FILENO); - } - - /* If we make it this far, we're a real daemon! Or we chose not to. */ - flog(LOG_INFO, "Proceeding with PID %d\n", getpid()); - return 0; -} - -/** - * Catch the SIGUSR2 signal and reload the rules configuration. This function - * makes use of the logfile and flog() to print the new rules. - * @param signum The signal that we caught (always SIGUSR2) - */ -void cgre_flash_rules(int signum) -{ - /* Current time */ - time_t tm = time(0); - - int fileindex; - - flog(LOG_INFO, "Reloading rules configuration\n"); - flog(LOG_DEBUG, "Current time: %s\n", ctime(&tm)); - - /* Ask libcgroup to reload the rules table. */ - cgroup_reload_cached_rules(); - - /* Print the results of the new table to our log file. */ - if (logfile && loglevel >= LOG_INFO) { - cgroup_print_rules_config(logfile); - fprintf(logfile, "\n"); - } - - /* Ask libcgroup to reload the template rules table. */ - cgroup_load_templates_cache_from_files(&fileindex); -} - -/** - * Catch the SIGUSR1 signal and reload the rules configuration. This function - * makes use of the logfile and flog() to print the new rules. - * @param signum The signal that we caught (always SIGUSR1) - */ -void cgre_flash_templates(int signum) -{ - /* Current time */ - time_t tm = time(0); - - int fileindex; - - flog(LOG_INFO, "Reloading templates configuration.\n"); - flog(LOG_DEBUG, "Current time: %s\n", ctime(&tm)); - - /* Ask libcgroup to reload the templates table. */ - cgroup_load_templates_cache_from_files(&fileindex); -} - -/** - * Catch the SIGTERM and SIGINT signals so that we can exit gracefully. Before - * exiting, this function makes use of the logfile and flog(). - * @param signum The signal that we caught (SIGTERM, SIGINT) - */ -void cgre_catch_term(int signum) -{ - /* Current time */ - time_t tm = time(0); - - flog(LOG_INFO, "Stopped CGroup Rules Engine Daemon at %s\n", - ctime(&tm)); - - /* Close the log file, if we opened one */ - if (logfile && logfile != stdout) - fclose(logfile); - - /* Close syslog */ - if (logfacility) - closelog(); - - exit(EXIT_SUCCESS); -} - -/** - * Parse the syslog facility as received on command line. - * @param arg Command line argument with the syslog facility - * @return the syslog facility (e.g. LOG_DAEMON) or 0 on error - */ -static int cgre_parse_syslog_facility(const char *arg) -{ - if (arg == NULL) - return 0; - - if (strlen(arg) > 1) - return 0; - - switch (arg[0]) { - case '0': - return LOG_LOCAL0; - case '1': - return LOG_LOCAL1; - case '2': - return LOG_LOCAL2; - case '3': - return LOG_LOCAL3; - case '4': - return LOG_LOCAL4; - case '5': - return LOG_LOCAL5; - case '6': - return LOG_LOCAL6; - case '7': - return LOG_LOCAL7; - case 'D': - return LOG_DAEMON; - default: - return 0; - } -} - -int main(int argc, char *argv[]) -{ - /* Patch to the log file */ - const char *logp = NULL; - - /* Syslog facility */ - int facility = 0; - - /* Verbose level */ - int verbosity = 1; - - /* For catching signals */ - struct sigaction sa; - - /* Should we daemonize? */ - unsigned char daemon = 1; - - /* Return codes */ - int ret = 0; - - struct passwd *pw; - struct group *gr; - - /* Command line arguments */ - const char *short_options = "hvqf:s::ndQu:g:"; - struct option long_options[] = { - {"help", no_argument, NULL, 'h'}, - {"verbose", no_argument, NULL, 'v'}, - {"quiet", no_argument, NULL, 'q'}, - {"logfile", required_argument, NULL, 'f'}, - {"syslog", optional_argument, NULL, 's'}, - {"nodaemon", no_argument, NULL, 'n'}, - {"debug", no_argument, NULL, 'd'}, - {"nolog", no_argument, NULL, 'Q'}, - {"socket-user", required_argument, NULL, 'u'}, - {"socket-group", required_argument, NULL, 'g'}, - {NULL, 0, NULL, 0} - }; - - int fileindex; - - /* Make sure the user is root. */ - if (getuid() != 0) { - fprintf(stderr, "Error: Only root can start/stop the control" - " group rules engine daemon\n"); - ret = 1; - goto finished; - } - - /* - * Check environment variable CGROUP_LOGLEVEL. If it's set to DEBUG, - * set appropriate verbosity level. - */ - char *level_str = getenv("CGROUP_LOGLEVEL"); - if (level_str != NULL) { - if (cgroup_parse_log_level_str(level_str) == CGROUP_LOG_DEBUG) { - verbosity = 4; - logp = "-"; - } - } - - while (1) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) - break; - - switch (c) { - case 'h': /* --help */ - usage(stdout, "Help:\n"); - ret = 0; - goto finished; - - case 'v': /* --verbose */ - verbosity++; - break; - - case 'q': /* --quiet */ - verbosity--; - break; - - case 'Q': /* --nolog */ - verbosity = 0; - break; - - case 'f': /* --logfile= */ - logp = optarg; - break; - - case 's': /* --syslog=[facility] */ - if (optarg) { - facility = cgre_parse_syslog_facility(optarg); - if (facility == 0) { - fprintf(stderr, - "Unknown syslog facility: %s\n", - optarg); - ret = 2; - goto finished; - } - } else { - facility = LOG_DAEMON; - } - break; - - case 'n': /* --no-fork */ - daemon = 0; - break; - - case 'd': /* --debug */ - /* same as -vvn */ - daemon = 0; - verbosity = 4; - logp = "-"; - break; - case 'u': /* --socket-user */ - pw = getpwnam(optarg); - if (pw == NULL) { - usage(stderr, "Cannot find user %s", optarg); - ret = 3; - goto finished; - } - socket_user = pw->pw_uid; - flog(LOG_DEBUG, "Using socket user %s id %d\n", - optarg, (int)socket_user); - break; - case 'g': /* --socket-group */ - gr = getgrnam(optarg); - if (gr == NULL) { - usage(stderr, "Cannot find group %s", optarg); - ret = 3; - goto finished; - } - socket_group = gr->gr_gid; - flog(LOG_DEBUG, "Using socket group %s id %d\n", - optarg, (int)socket_group); - break; - default: - usage(stderr, ""); - ret = 2; - goto finished; - } - } - - /* Initialize libcgroup. */ - if ((ret = cgroup_init()) != 0) { - fprintf(stderr, "Error: libcgroup initialization failed, %s\n", - cgroup_strerror(ret)); - goto finished; - } - - /* Ask libcgroup to load the configuration rules. */ - ret = cgroup_string_list_init(&template_files, - CGCONFIG_CONF_FILES_LIST_MINIMUM_SIZE); - if (ret) { - fprintf(stderr, "%s: cannot init file list, out of memory?\n", - argv[0]); - goto finished_without_temp_files; - } - /* first add CGCONFIG_CONF_FILE into file list */ - ret = cgroup_string_list_add_item(&template_files, CGCONFIG_CONF_FILE); - if (ret) { - fprintf(stderr, "%s: cannot add file to list, out of memory?\n" - , argv[0]); - goto finished; - } - - /* then read CGCONFIG_CONF_DIR directory for additional config files */ - cgroup_string_list_add_directory(&template_files, CGCONFIG_CONF_DIR, - argv[0]); - - if ((ret = cgroup_init_rules_cache()) != 0) { - fprintf(stderr, "Error: libcgroup failed to initialize rules" - "cache from %s. %s\n", CGRULES_CONF_FILE, - cgroup_strerror(ret)); - goto finished; - } - - /* ask libcgroup to load template rules as well */ - cgroup_templates_cache_set_source_files(&template_files); - ret = cgroup_load_templates_cache_from_files(&fileindex); - if (ret != 0) { - if (fileindex < 0) { - fprintf(stderr, "Error: Template source files "); - fprintf(stderr, "have not been set\n"); - } else { - fprintf(stderr, "Error: Failed to initialize template"); - fprintf(stderr, "rules from %s. ", - template_files.items[fileindex]); - fprintf(stderr, "%s\n", cgroup_strerror(-ret)); - } - goto finished; - } - - /* Now, start the daemon. */ - ret = cgre_start_daemon(logp, facility, daemon, verbosity); - if (ret < 0) { - fprintf(stderr, "Error: Failed to launch the daemon, %s\n", - cgroup_strerror(ret)); - goto finished; - } - - /* - * Set up the signal handler to reload the cached rules upon reception - * of a SIGUSR2 signal. - */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = &cgre_flash_rules; - sigemptyset(&sa.sa_mask); - if ((ret = sigaction(SIGUSR2, &sa, NULL))) { - flog(LOG_ERR, - "Failed to set up signal handler for SIGUSR2. Error: %s\n", - strerror(errno)); - goto finished; - } - - /* - * Set up the signal handler to reload templates cache upon - * reception of a SIGUSR1 signal. - */ - sa.sa_handler = &cgre_flash_templates; - ret = sigaction(SIGUSR1, &sa, NULL); - if (ret) { - flog(LOG_ERR, "Failed to set up signal handler for SIGUSR1."\ - " Error: %s\n", strerror(errno)); - goto finished; - } - - /* - * Set up the signal handler to catch SIGINT and SIGTERM so that we - * can exit gracefully. - */ - sa.sa_handler = &cgre_catch_term; - ret = sigaction(SIGINT, &sa, NULL); - ret |= sigaction(SIGTERM, &sa, NULL); - if (ret) { - flog(LOG_ERR, - "Failed to set up the signal handler. Error: %s\n", - strerror(errno)); - goto finished; - } - - /* Print the configuration to the log file, or stdout. */ - if (logfile && loglevel >= LOG_INFO) - cgroup_print_rules_config(logfile); - - /* Scan for running applications with rules */ - ret = cgroup_change_all_cgroups(); - if (ret) - flog(LOG_WARNING, "Failed to initialize running tasks.\n"); - - flog(LOG_INFO, "Started the CGroup Rules Engine Daemon.\n"); - - /* We loop endlesly in this function, unless we encounter an error. */ - ret = cgre_create_netlink_socket_process_msg(); - -finished: - cgroup_string_list_free(&template_files); - -finished_without_temp_files: - if (logfile && logfile != stdout) - fclose(logfile); - - return ret; -} diff --git a/src/daemon/cgrulesengd.h b/src/daemon/cgrulesengd.h deleted file mode 100644 index e273b4bc..00000000 --- a/src/daemon/cgrulesengd.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Red Hat Inc. 2008 - * - * Author: Steve Olivieri - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef _CGRULESENGD_H -#define _CGRULESENGD_H - -#include - -__BEGIN_DECLS - -#include "config.h" -#include "libcgroup.h" -#include -#include - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#ifndef __USE_GNU -#define __USE_GNU -#endif - -/* The following ten macros are all for the Netlink code. */ -#define SEND_MESSAGE_LEN (NLMSG_LENGTH(sizeof(struct cn_msg) + \ - sizeof(enum proc_cn_mcast_op))) -#define RECV_MESSAGE_LEN (NLMSG_LENGTH(sizeof(struct cn_msg) + \ - sizeof(struct proc_event))) - -#define SEND_MESSAGE_SIZE (NLMSG_SPACE(SEND_MESSAGE_LEN)) -#define RECV_MESSAGE_SIZE (NLMSG_SPACE(RECV_MESSAGE_LEN)) - -#define BUFF_SIZE (max(max(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE), 1024)) -#define MIN_RECV_SIZE (min(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE)) - -#define PROC_CN_MCAST_LISTEN (1) -#define PROC_CN_MCAST_IGNORE (2) - -/** - * Prints the usage information for this program and, optionally, an error - * message. This function uses vfprintf. - * @param fd The file stream to print to - * @param msg The error message to print (printf style) - * @param ... Any args to msg (printf style) - */ -void cgre_usage(FILE *fd, const char *msg, ...); - -/** - * Prints a formatted message (like printf()) to all log destinations. - * Flushes the file stream's buffer so that the message is immediately - * readable. - * @param level The log level (LOG_EMERG ... LOG_DEBUG) - * @param format The format for the message (printf style) - * @param ... Any args to format (printf style) - */ -void flog(int level, const char *msg, ...); - -/** - * Process an event from the kernel, and determine the correct UID/GID/PID to - * pass to libcgroup. Then, libcgroup will decide the cgroup to move the PID - * to, if any. - * @param ev The event to process - * @param type The type of event to process (part of ev) - * @return 0 on success, > 0 on failure - */ -int cgre_process_event(const struct proc_event *ev, const int type); - -/** - * Handle a netlink message. In the event of PROC_EVENT_UID or PROC_EVENT_GID, - * we pass the event along to cgre_process_event for further processing. All - * other events are ignored. - * @param cn_hdr The netlink message - * @return 0 on success, > 0 on error - */ -int cgre_handle_message(struct cn_msg *cn_hdr); - -/** - * Turns this program into a daemon. In doing so, we fork() and kill the - * parent process. Note too that stdout, stdin, and stderr are closed in - * daemon mode, and a file descriptor for a log file is opened. - * @param logp Path of the log file, NULL if no log file was specified - * @param logf Syslog facility, NULL if no facility was specified - * @param daemon False to turn off daemon mode (no fork, leave FDs open) - * @param logv Log verbosity, 2 is the default, 0 = no logging, 5 = everything - * @return 0 on success, > 0 on error - */ -int cgre_start_daemon(const char *logp, const int logf, - const unsigned char daemon, const int logv); - -/** - * Catch the SIGUSR2 signal and reload the rules configuration. This function - * makes use of the logfile and flog() to print the new rules. - * @param signum The signal that we caught (always SIGUSR2) - */ -void cgre_flash_rules(int signum); - -/** - * Catch the SIGUSR1 signal and reload the rules configuration. This function - * makes use of the logfile and flog() to print the new rules. - * @param signum The signal that we caught (always SIGUSR1) - */ -void cgre_flash_templates(int signum); - -/** - * Catch the SIGTERM and SIGINT signal so that we can exit gracefully. Before - * exiting, this function makes use of the logfile and flog(). - * @param signum The signal that we caught (SIGTERM, SIGINT) - */ -void cgre_catch_term(int signum); - -__END_DECLS - -#endif /* _CGRULESENGD_H */ - diff --git a/src/lex.l b/src/lex.l deleted file mode 100644 index ecd212c4..00000000 --- a/src/lex.l +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright IBM Corporation. 2007 - * - * Authors: Balbir Singh - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -%{ -#include -#include -#include -#include "parse.h" -#pragma GCC diagnostic ignored "-Wunused-function" - -int line_no = 1; -jmp_buf parser_error_env; - -#define YY_FATAL_ERROR(msg) \ - do { \ - fprintf(stderr, "%s\n", msg); \ - longjmp(parser_error_env, 1); \ - } while(0); -%} - -%option nounput noinput - -%% -\n {line_no++;} -[ \t] {/* DO NOTHING */} -^[ \t]*#.*[ \t]* {/* Comments */} -^\*.*[ \t]* {/* Comments */} -"mount" {return MOUNT;} -"task" {return TASK;} -"admin" {return ADMIN;} -"perm" {return PERM;} -"group" {return GROUP;} -"namespace" {return NAMESPACE;} -"template" {return TEMPLATE;} -"default" {yylval.name = strdup(yytext); return DEFAULT;} -[a-zA-Z0-9_\-\/\.\,\%\@\\]+ {yylval.name = strdup(yytext); return ID;} -\"[^"]*\" {yylval.name = strdup(yytext+1); yylval.name[strlen(yylval.name)-1] = '\0'; return ID; } -. {return yytext[0];} -%% - diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h deleted file mode 100644 index e31df512..00000000 --- a/src/libcgroup-internal.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright IBM Corporation. 2008 - * - * Author: Dhaval Giani - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ -#ifndef __LIBCG_INTERNAL - -#define __LIBCG_INTERNAL - -__BEGIN_DECLS - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include - -/* Maximum number of mount points/controllers */ -#define MAX_MNT_ELEMENTS 16 -/* Estimated number of groups created */ -#define MAX_GROUP_ELEMENTS 128 - -/* Maximum length of a value */ -#define CG_CONTROL_VALUE_MAX 4096 - -#define CG_NV_MAX 100 -#define CG_CONTROLLER_MAX 100 -#define CG_OPTIONS_MAX 100 -/* Max number of mounted hierarchies. Event if one controller is mounted per - * hier, it can not exceed CG_CONTROLLER_MAX - */ -#define CG_HIER_MAX CG_CONTROLLER_MAX - -/* Definitions for the uid and gid members of a cgroup_rules */ -/* FIXME: These really should not be negative values */ -#define CGRULE_INVALID ((uid_t) -1) -#define CGRULE_WILD ((uid_t) -2) - -#define CGRULE_SUCCESS_STORE_PID "SUCCESS_STORE_PID" - -/* Definitions for the cgrules options field */ -#define CGRULE_OPTION_IGNORE "ignore" - -#define CGCONFIG_CONF_FILE "/etc/cgconfig.conf" -/* Minimum number of file in template file list for cgrulesengd */ -#define CGCONFIG_CONF_FILES_LIST_MINIMUM_SIZE 4 -#define CGCONFIG_CONF_DIR "/etc/cgconfig.d" - -#define CGRULES_CONF_FILE "/etc/cgrules.conf" -#define CGRULES_CONF_DIR "/etc/cgrules.d" -#define CGRULES_MAX_FIELDS_PER_LINE 3 - -#define CGROUP_BUFFER_LEN (5 * FILENAME_MAX) - -/* Maximum length of a key(:) in the daemon config file */ -#define CGROUP_RULE_MAXKEY (LOGIN_NAME_MAX + FILENAME_MAX + 1) - -/* Maximum length of a line in the daemon config file */ -#define CGROUP_RULE_MAXLINE (FILENAME_MAX + CGROUP_RULE_MAXKEY + \ - CG_CONTROLLER_MAX + 3) - -#define cgroup_err(x...) cgroup_log(CGROUP_LOG_ERROR, x) -#define cgroup_warn(x...) cgroup_log(CGROUP_LOG_WARNING, x) -#define cgroup_info(x...) cgroup_log(CGROUP_LOG_INFO, x) -#define cgroup_dbg(x...) cgroup_log(CGROUP_LOG_DEBUG, x) - -#define CGROUP_DEFAULT_LOGLEVEL CGROUP_LOG_ERROR - -#define max(x,y) ((y)<(x)?(x):(y)) -#define min(x,y) ((y)>(x)?(x):(y)) - -struct control_value { - char name[FILENAME_MAX]; - char value[CG_CONTROL_VALUE_MAX]; - bool dirty; -}; - -struct cgroup_controller { - char name[FILENAME_MAX]; - struct control_value *values[CG_NV_MAX]; - struct cgroup *cgroup; - int index; -}; - -struct cgroup { - char name[FILENAME_MAX]; - struct cgroup_controller *controller[CG_CONTROLLER_MAX]; - int index; - uid_t tasks_uid; - gid_t tasks_gid; - mode_t task_fperm; - uid_t control_uid; - gid_t control_gid; - mode_t control_fperm; - mode_t control_dperm; -}; - -struct cg_mount_point { - char path[FILENAME_MAX]; - struct cg_mount_point *next; -}; - -struct cg_mount_table_s { - /** Controller name. */ - char name[FILENAME_MAX]; - /** - * List of mount points, at least one mount point is there for sure. - */ - struct cg_mount_point mount; - int index; -}; - -struct cgroup_rules_data { - pid_t pid; /* pid of the process which needs to change group */ - - /* Details of user under consideration for destination cgroup */ - struct passwd *pw; - /* Gid of the process */ - gid_t gid; -}; - -/* A rule that maps UID/GID to a cgroup */ -struct cgroup_rule { - uid_t uid; - gid_t gid; - bool is_ignore; - char *procname; - char username[LOGIN_NAME_MAX]; - char destination[FILENAME_MAX]; - char *controllers[MAX_MNT_ELEMENTS]; - struct cgroup_rule *next; -}; - -/* Container for a list of rules */ -struct cgroup_rule_list { - struct cgroup_rule *head; - struct cgroup_rule *tail; - int len; -}; - -/*The walk_tree handle */ -struct cgroup_tree_handle { - FTS *fts; - int flags; -}; - -/** - * Internal item of dictionary. Linked list is sufficient for now - we need - * only 'add' operation and simple iterator. In future, this might be easily - * rewritten to dynamic array when random access is needed, - * just keep in mind that the order is important and the iterator should - * return the items in the order they were added there. - */ -struct cgroup_dictionary_item { - const char *name; - const char *value; - struct cgroup_dictionary_item *next; -}; - -/* Flags for cgroup_dictionary_create */ -/** - * All items (i.e. both name and value strings) stored in the dictionary - * should *NOT* be free()d on cgroup_dictionary_free(), - * only the dictionary helper structures (i.e. underlying linked list) - * should be freed. - */ -#define CG_DICT_DONT_FREE_ITEMS 1 - -/** - * Dictionary of (name, value) items. - * The dictionary keeps its order, iterator iterates in the same order - * as the items were added there. It is *not* hash-style structure, - * it does not provide random access to its items nor quick search. - * This structure should be opaque to users of the dictionary, underlying data - * structure might change anytime and without warnings. - */ -struct cgroup_dictionary { - struct cgroup_dictionary_item *head; - struct cgroup_dictionary_item *tail; - int flags; -}; - -/** Opaque iterator of an dictionary. */ -struct cgroup_dictionary_iterator { - struct cgroup_dictionary_item *item; -}; - -/** - * per thread errno variable, to be used when return code is ECGOTHER - */ -extern __thread int last_errno; - -/** - * 'Exception handler' for lex parser. - */ -extern jmp_buf parser_error_env; - -/* Internal API */ -char *cg_build_path(const char *name, char *path, const char *type); -int cgroup_get_uid_gid_from_procfs(pid_t pid, uid_t *euid, gid_t *egid); -int cgroup_get_procname_from_procfs(pid_t pid, char **procname); -int cg_mkdir_p(const char *path); -struct cgroup *create_cgroup_from_name_value_pairs(const char *name, - struct control_value *name_value, int nv_number); -void init_cgroup_table(struct cgroup *cgroups, size_t count); - -/* - * Main mounting structures - */ -extern struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX]; -extern pthread_rwlock_t cg_mount_table_lock; - -/* - * config related structures - */ - -extern __thread char *cg_namespace_table[CG_CONTROLLER_MAX]; - -/* - * config related API - */ -int cgroup_config_insert_cgroup(char *cg_name); -int cgroup_config_parse_controller_options(char *controller, - struct cgroup_dictionary *values); -int template_config_insert_cgroup(char *cg_name); -int template_config_parse_controller_options(char *controller, - struct cgroup_dictionary *values); -int template_config_group_task_perm(char *perm_type, char *value); -int template_config_group_admin_perm(char *perm_type, char *value); -int cgroup_config_group_task_perm(char *perm_type, char *value); -int cgroup_config_group_admin_perm(char *perm_type, char *value); -int cgroup_config_insert_into_mount_table(char *name, char *mount_point); -int cgroup_config_insert_into_namespace_table(char *name, char *mount_point); -void cgroup_config_cleanup_mount_table(void); -void cgroup_config_cleanup_namespace_table(void); -int cgroup_config_define_default(void); - -/** - * Create an empty dictionary. - */ -extern int cgroup_dictionary_create(struct cgroup_dictionary **dict, - int flags); -/** - * Add an item to existing dictionary. - */ -extern int cgroup_dictionary_add(struct cgroup_dictionary *dict, - const char *name, const char *value); -/** - * Fully destroy existing dictionary. Depending on flags passed to - * cgroup_dictionary_create(), names and values might get destroyed too. - */ -extern int cgroup_dictionary_free(struct cgroup_dictionary *dict); - -/** - * Start iterating through a dictionary. The items are returned in the same - * order as they were added using cgroup_dictionary_add(). - */ -extern int cgroup_dictionary_iterator_begin(struct cgroup_dictionary *dict, - void **handle, const char **name, const char **value); -/** - * Continue iterating through the dictionary. - */ -extern int cgroup_dictionary_iterator_next(void **handle, - const char **name, const char **value); -/** - * Finish iteration through the dictionary. - */ -extern void cgroup_dictionary_iterator_end(void **handle); - -/** - * Changes permissions for given path. If owner_is_umask is specified - * then it uses owner permissions as a mask for group and others permissions. - * - * @param path Patch to chmod. - * @param mode File permissions to set. - * @param owner_is_umask Flag whether path owner permissions should be used - * as a mask for group and others permissions. - */ -int cg_chmod_path(const char *path, mode_t mode, int owner_is_umask); - -/** - * Functions that are defined as STATIC can be placed within the UNIT_TEST - * ifdef. This will allow them to be included in the unit tests while - * remaining static in a normal libcgroup library build. - */ -#ifdef UNIT_TEST - -#define TEST_PROC_PID_CGROUP_FILE "test-procpidcgroup" - -int cgroup_parse_rules_options(char *options, - struct cgroup_rule * const rule); - -int cg_get_cgroups_from_proc_cgroups(pid_t pid, char *cgroup_list[], - char *controller_list[], - int list_len); - -bool cgroup_compare_ignore_rule(const struct cgroup_rule * const rule, - pid_t pid, const char * const procname); - -bool cgroup_compare_wildcard_procname(const char * const rule_procname, - const char * const procname); - -#endif /* UNIT_TEST */ - -__END_DECLS - -#endif diff --git a/src/libcgroup.map b/src/libcgroup.map deleted file mode 100644 index 8fe19905..00000000 --- a/src/libcgroup.map +++ /dev/null @@ -1,131 +0,0 @@ -CGROUP_0.32 { -global: - cgroup_init; - cgroup_attach_task; - cgroup_modify_cgroup; - cgroup_create_cgroup; - cgroup_delete_cgroup; - cgroup_attach_task_pid; - cgroup_get_cgroup; - cgroup_create_cgroup_from_parent; - cgroup_copy_cgroup; - cgroup_change_cgroup_uid_gid; - cgroup_change_cgroup_path; - cgroup_new_cgroup; - cgroup_add_controller; - cgroup_free; - cgroup_free_controllers; - cgroup_add_value_string; - cgroup_add_value_int64; - cgroup_add_value_uint64; - cgroup_add_value_bool; - cgroup_compare_cgroup; - cgroup_compare_controllers; - cgroup_set_uid_gid; - cgroup_get_uid_gid; - cgroup_get_value_string; - cgroup_set_value_string; - cgroup_get_value_int64; - cgroup_set_value_int64; - cgroup_get_value_uint64; - cgroup_set_value_uint64; - cgroup_get_value_bool; - cgroup_set_value_bool; - cgroup_change_cgroup_uid_gid_flags; - cgroup_print_rules_config; - cgroup_reload_cached_rules; - cgroup_init_rules_cache; - cgroup_get_current_controller_path; - cgroup_config_load_config; -local: - *; -}; - -CGROUP_0.32.1 { -global: - cgroup_strerror; -} CGROUP_0.32; - -CGROUP_0.33 { -global: - cgroup_get_last_errno; - cgroup_walk_tree_begin; - cgroup_walk_tree_next; - cgroup_walk_tree_end; -} CGROUP_0.32.1; - -CGROUP_0.34 { -global: - cgroup_get_task_begin; - cgroup_get_task_end; - cgroup_get_task_next; - cgroup_read_stats_begin; - cgroup_read_stats_next; - cgroup_read_stats_end; - cgroup_walk_tree_set_flags; - cgroup_get_controller_end; - cgroup_get_controller_next; - cgroup_get_controller_begin; - cgroup_unload_cgroups; - cgroup_get_controller; - cgroup_get_uid_gid_from_procfs; - cgroup_get_subsys_mount_point; - cgroup_get_procname_from_procfs; - cgroup_register_unchanged_process; - cgroup_change_cgroup_flags; -} CGROUP_0.33; - -CGROUP_0.35 { -global: - create_cgroup_from_name_value_pairs; - cgroup_delete_cgroup_ext; - cgroup_get_all_controller_begin; - cgroup_get_all_controller_next; - cgroup_get_all_controller_end; - cgroup_get_value_name_count; - cgroup_get_value_name; -} CGROUP_0.34; - -CGROUP_0.36 { -} CGROUP_0.35; - -CGROUP_0.37 { - cgroup_get_procs; - cgroup_read_value_begin; - cgroup_read_value_next; - cgroup_read_value_end; - cg_chmod_recursive; -} CGROUP_0.36; - -CGROUP_0.38 { - cgroup_get_subsys_mount_point_begin; - cgroup_get_subsys_mount_point_next; - cgroup_get_subsys_mount_point_end; - cgroup_set_permissions; - cgroup_config_unload_config; - cgroup_config_set_default; -} CGROUP_0.37; - -CGROUP_0.39 { - cgroup_reload_cached_templates; - cgroup_init_templates_cache; - cgroup_config_create_template_group; - cgroup_change_all_cgroups; - cgroup_set_logger; - cgroup_set_default_logger; - cgroup_set_loglevel; - cgroup_log; - cgroup_parse_log_level_str; -} CGROUP_0.38; - -CGROUP_0.40 { - cgroup_templates_cache_set_source_files; - cgroup_load_templates_cache_from_files; -} CGROUP_0.39; - -CGROUP_0.41 { -} CGROUP_0.40; - -CGROUP_0.42 { - cgroup_add_all_controllers; -} CGROUP_0.41; diff --git a/src/log.c b/src/log.c deleted file mode 100644 index f6a386d4..00000000 --- a/src/log.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Red Hat, Inc. 2012 - * - * Author: Jan Safranek - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include -#include -#include -#include -#include -#include -#include - -static cgroup_logger_callback cgroup_logger; -static void *cgroup_logger_userdata; -static int cgroup_loglevel; - -static void cgroup_default_logger(void *userdata, int level, const char *fmt, - va_list ap) -{ - vfprintf(stdout, fmt, ap); -} - -void cgroup_log(int level, const char *fmt, ...) -{ - va_list ap; - - if (!cgroup_logger) - return; - - if (level > cgroup_loglevel) - return; - - va_start(ap, fmt); - cgroup_logger(cgroup_logger_userdata, level, fmt, ap); - va_end(ap); -} - -void cgroup_set_logger(cgroup_logger_callback logger, int loglevel, - void *userdata) -{ - cgroup_logger = logger; - cgroup_set_loglevel(loglevel); - cgroup_logger_userdata = userdata; -} - -void cgroup_set_default_logger(int level) -{ - if (!cgroup_logger) - cgroup_set_logger(cgroup_default_logger, level, NULL); -} - -int cgroup_parse_log_level_str(const char *levelstr) -{ - char *end; - long level; - errno = 0; - - /* try to parse integer first */ - level = strtol(levelstr, &end, 10); - if (end != levelstr && *end == '\0') - return level; - - if (strcasecmp(levelstr, "ERROR") == 0) - return CGROUP_LOG_ERROR; - if (strcasecmp(levelstr, "WARNING") == 0) - return CGROUP_LOG_WARNING; - if (strcasecmp(levelstr, "INFO") == 0) - return CGROUP_LOG_INFO; - if (strcasecmp(levelstr, "DEBUG") == 0) - return CGROUP_LOG_DEBUG; - - return CGROUP_DEFAULT_LOGLEVEL; -} - -void cgroup_set_loglevel(int loglevel) -{ - if (loglevel != -1) - cgroup_loglevel = loglevel; - else { - char *level_str = getenv("CGROUP_LOGLEVEL"); - if (level_str != NULL) - cgroup_loglevel = cgroup_parse_log_level_str(level_str); - else - cgroup_loglevel = CGROUP_DEFAULT_LOGLEVEL; - } -} diff --git a/src/pam/Makefile.am b/src/pam/Makefile.am deleted file mode 100644 index 5566cd7b..00000000 --- a/src/pam/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -INCLUDES = -I $(top_srcdir)/include - -if WITH_PAM - -pamlib_LTLIBRARIES = pam_cgroup.la -pam_cgroup_la_SOURCES = pam_cgroup.c -pam_cgroup_la_LDFLAGS = -module -pam_cgroup_la_LIBADD = $(top_builddir)/src/.libs/libcgroup.la -lpam - -endif diff --git a/src/pam/pam_cgroup.c b/src/pam/pam_cgroup.c deleted file mode 100644 index 1d78b814..00000000 --- a/src/pam/pam_cgroup.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright RedHat Inc. 2008 - * - * Author: Vivek Goyal - * - * Derived from pam_limits.c. Original Copyright notice follows. - * - * Copyright (c) Cristian Gafton, 1996-1997, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * End of original copyright notice. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Module defines - */ - -#define PAM_SM_SESSION - -#include -#include -#include -#include - -/* argument parsing */ - -#define PAM_DEBUG_ARG 0x0001 - -static int _pam_parse(const pam_handle_t *pamh, int argc, const char **argv) -{ - int ctrl = 0; - - /* step through arguments */ - for (ctrl = 0; argc-- > 0; ++argv) { - if (!strcmp(*argv, "debug")) - ctrl |= PAM_DEBUG_ARG; - else - pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); - } - - return ctrl; -} - -/* now the session stuff */ -PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, - int argc, const char **argv) -{ - pid_t pid; - int ctrl, ret; - char *user_name; - struct passwd *pwd; - - D(("called.")); - - ctrl = _pam_parse(pamh, argc, argv); - - ret = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || ret != PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "open_session - error recovering" - "username"); - return PAM_SESSION_ERR; - } - - pwd = pam_modutil_getpwnam(pamh, user_name); - if (!pwd) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_ERR, "open_session username" - " '%s' does not exist", user_name); - return PAM_SESSION_ERR; - } - - D(("user name is %s", user_name)); - - /* Initialize libcg */ - ret = cgroup_init(); - if (ret) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_ERR, "libcgroup initialization" - " failed"); - return PAM_SESSION_ERR; - } - - D(("Initialized libcgroup successfuly.")); - - /* Determine the pid of the task */ - pid = getpid(); - - /* Note: We are using default gid here. Is there a way to determine - * under what egid service will be provided? - */ - ret = cgroup_change_cgroup_uid_gid_flags(pwd->pw_uid, - pwd->pw_gid, pid, CGFLAG_USECACHE); - if (ret) { - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_ERR, "Change of cgroup for process" - " with username %s failed.\n", user_name); - return PAM_SESSION_ERR; - } - - if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_DEBUG, "Changed cgroup for process %d" - " with username %s.\n", pid, user_name); - - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, - const char **argv) -{ - D(("called pam_cgroup close session")); - - /* nothing to do yet */ - return PAM_SUCCESS; -} diff --git a/src/parse.y b/src/parse.y deleted file mode 100644 index e67ad54e..00000000 --- a/src/parse.y +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright IBM Corporation. 2007 - * - * Authors: Balbir Singh - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * NOTE: The grammar has been modified, not to be the most efficient, but - * to allow easy updation of internal data structures. - */ -%{ -#include -#include -#include -#include -#include - -int yylex(void); -extern int line_no; -extern char *yytext; - -static void yyerror(const char *s) -{ - fprintf(stderr, "error at line number %d at %s:%s\n", line_no, yytext, - s); -} - -int yywrap(void) -{ - return 1; -} - -%} - -%token ID MOUNT GROUP PERM TASK ADMIN NAMESPACE DEFAULT TEMPLATE - -%union { - char *name; - char chr; - int val; - struct cgroup_dictionary *values; -} -%type ID DEFAULT group_name -%type mountvalue_conf mount task_namevalue_conf admin_namevalue_conf -%type admin_conf task_conf task_or_admin group_conf group start -%type namespace namespace_conf default default_conf -%type namevalue_conf -%type template template_conf -%type template_task_or_admin template_task_namevalue_conf -%type template_admin_namevalue_conf template_task_conf -%type template_admin_conf -%start start -%% - -start : start group - { - $$ = $1; - } - | start mount - { - $$ = $1; - } - | start default - { - $$ = $1; - } - | start namespace - { - $$ = $1; - } - | start template - { - $$ = $1; - } - | - { - $$ = 1; - } - ; - -default : DEFAULT '{' default_conf '}' - { - $$ = $3; - if ($$) { - cgroup_config_define_default(); - } - } - ; - -default_conf - : PERM '{' task_or_admin '}' - { - $$ = $3; - } - ; - -group : GROUP group_name '{' group_conf '}' - { - $$ = $4; - if ($$) { - $$ = cgroup_config_insert_cgroup($2); - if (!$$) { - fprintf(stderr, "failed to insert group" - " check size and memory"); - $$ = ECGOTHER; - return $$; - } - } else { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -group_name - : ID - { - $$ = $1; - } - | DEFAULT - { - $$ = $1; - } - -group_conf - : ID '{' namevalue_conf '}' - { - $$ = cgroup_config_parse_controller_options($1, $3); - cgroup_dictionary_free($3); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | group_conf ID '{' namevalue_conf '}' - { - $$ = cgroup_config_parse_controller_options($2, $4); - cgroup_dictionary_free($4); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | PERM '{' task_or_admin '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -template : TEMPLATE ID '{' template_conf '}' - { - $$ = $4; - if ($$) { - $$ = template_config_insert_cgroup($2); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGOTHER; - return $$; - } - } else { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - - -template_conf - : ID '{' namevalue_conf '}' - { - $$ = template_config_parse_controller_options($1, $3); - cgroup_dictionary_free($3); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | template_conf ID '{' namevalue_conf '}' - { - $$ = template_config_parse_controller_options($2, $4); - cgroup_dictionary_free($4); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | PERM '{' template_task_or_admin '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -template_task_or_admin - : TASK '{' template_task_namevalue_conf '}' template_admin_conf - { - $$ = $3 && $5; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | ADMIN '{' template_admin_namevalue_conf '}' template_task_conf - { - $$ = $3 && $5; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - - -namevalue_conf - : ID '=' ID ';' - { - struct cgroup_dictionary *dict; - int ret; - ret = cgroup_dictionary_create(&dict, 0); - if (ret == 0) - ret = cgroup_dictionary_add(dict, $1, $3); - if (ret) { - fprintf(stderr, "parsing failed at line number %d:%s\n", - line_no, cgroup_strerror(ret)); - $$ = NULL; - cgroup_dictionary_free(dict); - return ECGCONFIGPARSEFAIL; - } - $$ = dict; - } - | namevalue_conf ID '=' ID ';' - { - int ret = 0; - ret = cgroup_dictionary_add($1, $2, $4); - if (ret != 0) { - fprintf(stderr, "parsing failed at line number %d: %s\n", - line_no, cgroup_strerror(ret)); - $$ = NULL; - return ECGCONFIGPARSEFAIL; - } - $$ = $1; - } - | - { - $$ = NULL; - } - ; - -task_namevalue_conf - : ID '=' ID ';' - { - $$ = cgroup_config_group_task_perm($1, $3); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | task_namevalue_conf ID '=' ID ';' - { - $$ = $1 && cgroup_config_group_task_perm($2, $4); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -admin_namevalue_conf - : ID '=' ID ';' - { - $$ = cgroup_config_group_admin_perm($1, $3); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | admin_namevalue_conf ID '=' ID ';' - { - $$ = $1 && cgroup_config_group_admin_perm($2, $4); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -template_task_namevalue_conf - : ID '=' ID ';' - { - $$ = template_config_group_task_perm($1, $3); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | template_task_namevalue_conf ID '=' ID ';' - { - $$ = $1 && template_config_group_task_perm($2, $4); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -template_admin_namevalue_conf - : ID '=' ID ';' - { - $$ = template_config_group_admin_perm($1, $3); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | template_admin_namevalue_conf ID '=' ID ';' - { - $$ = $1 && template_config_group_admin_perm($2, $4); - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - - -task_or_admin - : TASK '{' task_namevalue_conf '}' admin_conf - { - $$ = $3 && $5; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - | ADMIN '{' admin_namevalue_conf '}' task_conf - { - $$ = $3 && $5; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -admin_conf: ADMIN '{' admin_namevalue_conf '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -task_conf: TASK '{' task_namevalue_conf '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -template_admin_conf: ADMIN '{' template_admin_namevalue_conf '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -template_task_conf: TASK '{' template_task_namevalue_conf '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -mountvalue_conf - : ID '=' ID ';' - { - if (!cgroup_config_insert_into_mount_table($1, $3)) { - cgroup_config_cleanup_mount_table(); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - $$ = 1; - } - | mountvalue_conf ID '=' ID ';' - { - if (!cgroup_config_insert_into_mount_table($2, $4)) { - cgroup_config_cleanup_mount_table(); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - $$ = 1; - } - ; - -mount : MOUNT '{' mountvalue_conf '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -namespace_conf - : ID '=' ID ';' - { - if (!cgroup_config_insert_into_namespace_table($1, $3)) { - cgroup_config_cleanup_namespace_table(); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - $$ = 1; - } - | namespace_conf ID '=' ID ';' - { - if (!cgroup_config_insert_into_namespace_table($2, $4)) { - cgroup_config_cleanup_namespace_table(); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - $$ = 1; - } - ; - -namespace : NAMESPACE '{' namespace_conf '}' - { - $$ = $3; - if (!$$) { - fprintf(stderr, "parsing failed at line number %d\n", - line_no); - $$ = ECGCONFIGPARSEFAIL; - return $$; - } - } - ; - -%% diff --git a/src/tools/.gitignore b/src/tools/.gitignore deleted file mode 100644 index d87e9452..00000000 --- a/src/tools/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -cgclassify -cgclear -cgconfigparser -cgcreate -cgdelete -cgexec -cgget -cgset -cgsnapshot -lscgroup -lssubsys diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am deleted file mode 100644 index 2f3534ce..00000000 --- a/src/tools/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -@CODE_COVERAGE_RULES@ - -INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/include -LDADD = $(top_builddir)/src/.libs/libcgroup.la - -if WITH_TOOLS - -bin_PROGRAMS = cgexec cgclassify cgcreate cgset cgget cgdelete lssubsys\ - lscgroup cgsnapshot - -sbin_PROGRAMS = cgconfigparser cgclear - -cgexec_SOURCES = cgexec.c tools-common.c tools-common.h -cgexec_LIBS = $(CODE_COVERAGE_LIBS) -cgexec_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgclassify_SOURCES = cgclassify.c tools-common.c tools-common.h -cgclassify_LIBS = $(CODE_COVERAGE_LIBS) -cgclassify_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgcreate_SOURCES = cgcreate.c tools-common.c tools-common.h -cgcreate_LIBS = $(CODE_COVERAGE_LIBS) -cgcreate_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgset_SOURCES = cgset.c tools-common.c tools-common.h -cgset_LIBS = $(CODE_COVERAGE_LIBS) -cgset_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgget_SOURCES = cgget.c tools-common.c tools-common.h -cgget_LIBS = $(CODE_COVERAGE_LIBS) -cgget_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgconfigparser_SOURCES = cgconfig.c tools-common.c tools-common.h -cgconfigparser_LIBS = $(CODE_COVERAGE_LIBS) -cgconfigparser_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgclear_SOURCES = cgclear.c tools-common.c tools-common.h -cgclear_LIBS = $(CODE_COVERAGE_LIBS) -cgclear_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgdelete_SOURCES = cgdelete.c tools-common.c tools-common.h -cgdelete_LIBS = $(CODE_COVERAGE_LIBS) -cgdelete_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -lssubsys_SOURCES = lssubsys.c -lssubsys_LIBS = $(CODE_COVERAGE_LIBS) -lssubsys_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -lscgroup_SOURCES = tools-common.c lscgroup.c -lscgroup_LIBS = $(CODE_COVERAGE_LIBS) -lscgroup_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -cgsnapshot_SOURCES = cgsnapshot.c -cgsnapshot_LIBS = $(CODE_COVERAGE_LIBS) -cgsnapshot_CFLAGS = $(CODE_COVERAGE_CFLAGS) - -install-exec-hook: - chmod u+s $(DESTDIR)$(bindir)/cgexec - -endif diff --git a/src/tools/cgclassify.c b/src/tools/cgclassify.c deleted file mode 100644 index 0a197152..00000000 --- a/src/tools/cgclassify.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright RedHat Inc. 2008 - * - * Authors: Vivek Goyal - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tools-common.h" - -#define TEMP_BUF 81 - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [[-g] :] "\ - "[--sticky | --cancel-sticky] \n", program_name); - printf("Move running task(s) to given cgroups\n"); - printf(" -h, --help Display this help\n"); - printf(" -g : Control group to be used "\ - "as target\n"); - printf(" --cancel-sticky cgred daemon change pidlist "\ - "and children tasks\n"); - printf(" --sticky cgred daemon does not change "\ - "pidlist and children tasks\n"); -} - -/* - * Change process group as specified on command line. - */ -static int change_group_path(pid_t pid, struct cgroup_group_spec *cgroup_list[]) -{ - int i; - int ret = 0; - - for (i = 0; i < CG_HIER_MAX; i++) { - if (!cgroup_list[i]) - break; - - ret = cgroup_change_cgroup_path(cgroup_list[i]->path, pid, - (const char*const*) cgroup_list[i]->controllers); - if (ret) { - fprintf(stderr, "Error changing group of pid %d: %s\n", - pid, cgroup_strerror(ret)); - return -1; - } - } - - return 0; -} - -/* - * Change process group as specified in cgrules.conf. - */ -static int change_group_based_on_rule(pid_t pid) -{ - uid_t euid; - gid_t egid; - char *procname = NULL; - int ret = -1; - - /* Put pid into right cgroup as per rules in /etc/cgrules.conf */ - if (cgroup_get_uid_gid_from_procfs(pid, &euid, &egid)) { - fprintf(stderr, "Error in determining euid/egid of" - " pid %d\n", pid); - goto out; - } - ret = cgroup_get_procname_from_procfs(pid, &procname); - if (ret) { - fprintf(stderr, "Error in determining process name of" - " pid %d\n", pid); - goto out; - } - - /* Change the cgroup by determining the rules */ - ret = cgroup_change_cgroup_flags(euid, egid, procname, pid, 0); - if (ret) { - fprintf(stderr, "Error: change of cgroup failed for" - " pid %d: %s\n", pid, cgroup_strerror(ret)); - goto out; - } - ret = 0; -out: - if (procname) - free(procname); - return ret; -} - -static struct option longopts[] = { - {"sticky", no_argument, NULL, 's'}, - {"cancel-sticky", no_argument, NULL, 'u'}, - {"help", no_argument, NULL, 'h'}, - {0, 0, 0, 0} -}; - -int main(int argc, char *argv[]) -{ - int ret = 0, i, exit_code = 0; - pid_t pid; - int cg_specified = 0; - int flag = 0; - struct cgroup_group_spec *cgroup_list[CG_HIER_MAX]; - int c; - char *endptr; - - - if (argc < 2) { - usage(1, argv[0]); - exit(2); - } - - memset(cgroup_list, 0, sizeof(cgroup_list)); - while ((c = getopt_long(argc, argv, "+g:sh", longopts, NULL)) > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - exit(0); - break; - case 'g': - ret = parse_cgroup_spec(cgroup_list, optarg, - CG_HIER_MAX); - if (ret) { - fprintf(stderr, "cgroup controller and path" - "parsing failed\n"); - return -1; - } - cg_specified = 1; - break; - case 's': - flag |= CGROUP_DAEMON_UNCHANGE_CHILDREN; - break; - case 'u': - flag |= CGROUP_DAEMON_CANCEL_UNCHANGE_PROCESS; - break; - default: - usage(1, argv[0]); - exit(2); - break; - } - } - - - /* Initialize libcg */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "%s: libcgroup initialization failed: %s\n", - argv[0], cgroup_strerror(ret)); - return ret; - } - - for (i = optind; i < argc; i++) { - pid = (pid_t) strtol(argv[i], &endptr, 10); - if (endptr[0] != '\0') { - /* the input argument was not a number */ - fprintf(stderr, "Error: %s is not valid pid.\n", - argv[i]); - exit_code = 2; - continue; - } - - if (flag) - ret = cgroup_register_unchanged_process(pid, flag); - if (ret) - exit_code = 1; - - if (cg_specified) - ret = change_group_path(pid, cgroup_list); - else - ret = change_group_based_on_rule(pid); - - /* if any group change fails */ - if (ret) - exit_code = 1; - } - return exit_code; - -} diff --git a/src/tools/cgclear.c b/src/tools/cgclear.c deleted file mode 100644 index 27cc47ac..00000000 --- a/src/tools/cgclear.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright IBM Corporation. 2009 - * - * Authors: Dhaval Giani - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Code initiated and designed by Dhaval Giani. All faults are most likely - * his mistake. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "tools-common.h" - -static struct cgroup_string_list cfg_files; - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-h] [-l FILE] [-L DIR] [-e]\n", - program_name); - printf("Unload the cgroup filesystem\n"); - printf(" -e, --empty Remove only empty cgroups\n"); - printf(" -h, --help Display this help\n"); - printf(" -l, --load=FILE Parse and load the cgroups "\ - "configuration file\n"); - printf(" -L, --load-directory=DIR Parse and load the cgroups "\ - "configuration files from a directory\n"); -} - -static void report_error(int error, const char *program_name) -{ - /* Don't spit an error when there is nothing to clear. */ - if (error == ECGROUPNOTMOUNTED) - error = 0; - if (error) { - printf("%s failed with %s\n", program_name, - cgroup_strerror(error)); - } -} - - -int main(int argc, char *argv[]) -{ - int error = 0, ret; - int c; - int unload_all = 1; - int flags = CGFLAG_DELETE_RECURSIVE; - - struct option longopts[] = { - {"load", required_argument, 0, 'l' }, - {"load-directory", required_argument, 0, 'L' }, - {"only-empty", no_argument, 0, 'e' }, - {"help", no_argument, 0, 'h'}, - { 0, 0, 0, 0} - }; - - ret = cgroup_string_list_init(&cfg_files, argc/2); - if (ret) { - fprintf(stderr, "%s: cannot initialize list of files," - " out of memory?\n", - argv[0]); - exit(1); - } - - while ((c = getopt_long(argc, argv, "hl:L:e", longopts, NULL)) > 0) { - switch (c) { - case 'e': - flags = CGFLAG_DELETE_EMPTY_ONLY; - break; - - case 'l': - unload_all = 0; - ret = cgroup_string_list_add_item(&cfg_files, optarg); - if (ret) { - fprintf(stderr, "%s: cannot add file to list,"\ - " out of memory?\n", argv[0]); - exit(1); - } - break; - - case 'L': - unload_all = 0; - cgroup_string_list_add_directory(&cfg_files, optarg, - argv[0]); - break; - - case 'h': - usage(0, argv[0]); - exit(0); - default: - usage(1, argv[0]); - exit(1); - } - } - - if (unload_all) { - error = cgroup_unload_cgroups(); - if (error) - report_error(error, argv[0]); - } else { - int i; - - ret = cgroup_init(); - if (ret) { - report_error(ret, argv[0]); - exit(4); - } - /* process the config files in reverse order */ - for (i = cfg_files.count-1; i >= 0 ; i--) { - ret = cgroup_config_unload_config(cfg_files.items[i], - flags); - if (ret && ret != ECGNONEMPTY) { - report_error(ret, argv[0]); - if (!error) - error = ret; - } - } - } - cgroup_string_list_free(&cfg_files); - if (error) - exit(3); - - return 0; -} diff --git a/src/tools/cgconfig.c b/src/tools/cgconfig.c deleted file mode 100644 index e8bb5a2e..00000000 --- a/src/tools/cgconfig.c +++ /dev/null @@ -1,206 +0,0 @@ - -/* - * Copyright IBM Corporation. 2007 - * - * Authors: Dhaval Giani - * Balbir Singh - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Code initiated and designed by Dhaval Giani. All faults are most likely - * his mistake. - */ - -#include -#include - -/* For basename() */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include - -#include -#include -#include -#include -#include "tools-common.h" - -static struct cgroup_string_list cfg_files; - -static void usage(int status, char *progname) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters, "\ - "try %s -h' for more information.\n", progname); - return; - } - printf("Usage: %s [-h] [-f mode] [-d mode] [-s mode] "\ - "[-t :] [-a :] [-l FILE] "\ - "[-L DIR] ...\n", progname); - printf("Parse and load the specified cgroups configuration file\n"); - printf(" -a : Default owner of groups files "\ - "and directories\n"); - printf(" -d, --dperm=mode Default group directory "\ - "permissions\n"); - printf(" -f, --fperm=mode Default group file "\ - "permissions\n"); - printf(" -h, --help Display this help\n"); - printf(" -l, --load=FILE Parse and load the cgroups "\ - "configuration file\n"); - printf(" -L, --load-directory=DIR Parse and load the cgroups "\ - "configuration files from a directory\n"); - printf(" -s, --tperm=mode Default tasks file "\ - "permissions\n"); - printf(" -t : Default owner of the tasks "\ - "file\n"); -} - -int main(int argc, char *argv[]) -{ - int c, i; - int ret, error = 0; - static struct option options[] = { - {"help", 0, 0, 'h'}, - {"load", 1, 0, 'l'}, - {"load-directory", 1, 0, 'L'}, - {"task", required_argument, NULL, 't'}, - {"admin", required_argument, NULL, 'a'}, - {"dperm", required_argument, NULL, 'd'}, - {"fperm", required_argument, NULL, 'f' }, - {"tperm", required_argument, NULL, 's' }, - {0, 0, 0, 0} - }; - uid_t tuid = NO_UID_GID, auid = NO_UID_GID; - gid_t tgid = NO_UID_GID, agid = NO_UID_GID; - mode_t dir_mode = NO_PERMS; - mode_t file_mode = NO_PERMS; - mode_t tasks_mode = NO_PERMS; - int dirm_change = 0; - int filem_change = 0; - struct cgroup *default_group = NULL; - - cgroup_set_default_logger(-1); - - if (argc < 2) { - usage(1, argv[0]); - return -1; - } - - error = cgroup_string_list_init(&cfg_files, argc/2); - if (error) - goto err; - - while ((c = getopt_long(argc, argv, "hl:L:t:a:d:f:s:", options, - NULL)) > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - error = 0; - goto err; - case 'l': - error = cgroup_string_list_add_item(&cfg_files, optarg); - if (error) { - fprintf(stderr, "%s: cannot add file to list,"\ - " out of memory?\n", argv[0]); - goto err; - } - break; - case 'L': - cgroup_string_list_add_directory(&cfg_files, optarg, - argv[0]); - break; - case 'a': - /* set admin uid/gid */ - error = parse_uid_gid(optarg, &auid, &agid, argv[0]); - if (error) - goto err; - break; - case 't': - /* set task uid/gid */ - error = parse_uid_gid(optarg, &tuid, &tgid, argv[0]); - if (error) - goto err; - break; - case 'd': - dirm_change = 1; - error = parse_mode(optarg, &dir_mode, argv[0]); - if (error) - goto err; - break; - case 'f': - filem_change = 1; - error = parse_mode(optarg, &file_mode, argv[0]); - if (error) - goto err; - break; - case 's': - filem_change = 1; - error = parse_mode(optarg, &tasks_mode, argv[0]); - if (error) - goto err; - break; - default: - usage(1, argv[0]); - error = -1; - goto err; - } - } - - if (argv[optind]) { - usage(1, argv[0]); - error = -1; - goto err; - } - - /* set default permissions */ - default_group = cgroup_new_cgroup("default"); - if (!default_group) { - error = -1; - fprintf(stderr, "%s: cannot create default cgroup\n", argv[0]); - goto err; - } - - error = cgroup_set_uid_gid(default_group, tuid, tgid, auid, agid); - if (error) { - fprintf(stderr, "%s: cannot set default UID and GID: %s\n", - argv[0], cgroup_strerror(error)); - goto free_cgroup; - } - - if (dirm_change | filem_change) { - cgroup_set_permissions(default_group, dir_mode, file_mode, - tasks_mode); - } - - error = cgroup_config_set_default(default_group); - if (error) { - fprintf(stderr, "%s: cannot set config parser defaults: %s\n", - argv[0], cgroup_strerror(error)); - goto free_cgroup; - } - - for (i = 0; i < cfg_files.count; i++) { - ret = cgroup_config_load_config(cfg_files.items[i]); - if (ret) { - fprintf(stderr, "%s; error loading %s: %s\n", argv[0], - cfg_files.items[i], - cgroup_strerror(ret)); - if (!error) - error = ret; - } - } - -free_cgroup: - cgroup_free(&default_group); -err: - cgroup_string_list_free(&cfg_files); - return error; -} diff --git a/src/tools/cgcreate.c b/src/tools/cgcreate.c deleted file mode 100644 index 65b188a9..00000000 --- a/src/tools/cgcreate.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright Red Hat, Inc. 2009 - * - * Authors: Ivana Hutarova Varekova - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tools-common.h" - -/* - * Display the usage - */ -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-h] [-f mode] [-d mode] [-s mode] "\ - "[-t :] [-a :] "\ - "-g : [-g ...]\n", program_name); - printf("Create control group(s)\n"); - printf(" -a : Owner of the group and all "\ - "its files\n"); - printf(" -d, --dperm=mode Group directory permissions\n"); - printf(" -f, --fperm=mode Group file permissions\n"); - printf(" -g : Control group which should be "\ - "added\n"); - printf(" -h, --help Display this help\n"); - printf(" -s, --tperm=mode Tasks file permissions\n"); - printf(" -t : Owner of the tasks file\n"); -} - -int main(int argc, char *argv[]) -{ - int ret = 0; - int i, j; - int c; - - static struct option long_opts[] = { - {"help", no_argument, NULL, 'h'}, - {"task", required_argument, NULL, 't'}, - {"admin", required_argument, NULL, 'a'}, - {"", required_argument, NULL, 'g'}, - {"dperm", required_argument, NULL, 'd'}, - {"fperm", required_argument, NULL, 'f' }, - {"tperm", required_argument, NULL, 's' }, - {0, 0, 0, 0}, - }; - - uid_t tuid = CGRULE_INVALID, auid = CGRULE_INVALID; - gid_t tgid = CGRULE_INVALID, agid = CGRULE_INVALID; - - struct cgroup_group_spec **cgroup_list; - struct cgroup *cgroup; - struct cgroup_controller *cgc; - - /* approximation of max. numbers of groups that will be created */ - int capacity = argc; - - /* permission variables */ - mode_t dir_mode = NO_PERMS; - mode_t file_mode = NO_PERMS; - mode_t tasks_mode = NO_PERMS; - int dirm_change = 0; - int filem_change = 0; - - /* no parametr on input */ - if (argc < 2) { - usage(1, argv[0]); - return -1; - } - cgroup_list = calloc(capacity, sizeof(struct cgroup_group_spec *)); - if (cgroup_list == NULL) { - fprintf(stderr, "%s: out of memory\n", argv[0]); - ret = -1; - goto err; - } - - /* parse arguments */ - while ((c = getopt_long(argc, argv, "a:t:g:hd:f:s:", long_opts, NULL)) - > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - ret = 0; - goto err; - case 'a': - /* set admin uid/gid */ - if (parse_uid_gid(optarg, &auid, &agid, argv[0])) - goto err; - break; - case 't': - /* set task uid/gid */ - if (parse_uid_gid(optarg, &tuid, &tgid, argv[0])) - goto err; - break; - case 'g': - ret = parse_cgroup_spec(cgroup_list, optarg, capacity); - if (ret) { - fprintf(stderr, "%s: " - "cgroup controller and path" - "parsing failed (%s)\n", - argv[0], argv[optind]); - ret = -1; - goto err; - } - break; - case 'd': - dirm_change = 1; - ret = parse_mode(optarg, &dir_mode, argv[0]); - if (ret) - goto err; - break; - case 'f': - filem_change = 1; - ret = parse_mode(optarg, &file_mode, argv[0]); - if (ret) - goto err; - break; - case 's': - filem_change = 1; - ret = parse_mode(optarg, &tasks_mode, argv[0]); - if (ret) - goto err; - break; - default: - usage(1, argv[0]); - ret = -1; - goto err; - } - } - - /* no cgroup name */ - if (argv[optind]) { - fprintf(stderr, "%s: " - "wrong arguments (%s)\n", - argv[0], argv[optind]); - ret = -1; - goto err; - } - - /* initialize libcg */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "%s: " - "libcgroup initialization failed: %s\n", - argv[0], cgroup_strerror(ret)); - goto err; - } - - /* for each new cgroup */ - for (i = 0; i < capacity; i++) { - if (!cgroup_list[i]) - break; - - /* create the new cgroup structure */ - cgroup = cgroup_new_cgroup(cgroup_list[i]->path); - if (!cgroup) { - ret = ECGFAIL; - fprintf(stderr, "%s: can't add new cgroup: %s\n", - argv[0], cgroup_strerror(ret)); - goto err; - } - - /* set uid and gid for the new cgroup based on input options */ - ret = cgroup_set_uid_gid(cgroup, tuid, tgid, auid, agid); - if (ret) - goto err; - - /* add controllers to the new cgroup */ - j = 0; - while (cgroup_list[i]->controllers[j]) { - if (strcmp(cgroup_list[i]->controllers[j], "*") == 0) { - /* it is meta character, add all controllers */ - ret = cgroup_add_all_controllers(cgroup); - if (ret != 0) { - ret = ECGINVAL; - fprintf(stderr, "%s: can't add ", - argv[0]); - fprintf(stderr, "all controllers\n"); - cgroup_free(&cgroup); - goto err; - } - } else { - cgc = cgroup_add_controller(cgroup, - cgroup_list[i]->controllers[j]); - if (!cgc) { - ret = ECGINVAL; - fprintf(stderr, "%s: ", argv[0]); - fprintf(stderr, "controller %s", - cgroup_list[i]->controllers[j]); - fprintf(stderr, "can't be add\n"); - cgroup_free(&cgroup); - goto err; - } - } - j++; - } - - /* all variables set so create cgroup */ - if (dirm_change | filem_change) - cgroup_set_permissions(cgroup, dir_mode, file_mode, - tasks_mode); - ret = cgroup_create_cgroup(cgroup, 0); - if (ret) { - fprintf(stderr, "%s: " - "can't create cgroup %s: %s\n", - argv[0], cgroup->name, cgroup_strerror(ret)); - cgroup_free(&cgroup); - goto err; - } - cgroup_free(&cgroup); - } -err: - if (cgroup_list) { - for (i = 0; i < capacity; i++) { - if (cgroup_list[i]) - cgroup_free_group_spec(cgroup_list[i]); - } - free(cgroup_list); - } - return ret; -} diff --git a/src/tools/cgdelete.c b/src/tools/cgdelete.c deleted file mode 100644 index 43cc47c2..00000000 --- a/src/tools/cgdelete.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright RedHat Inc. 2009 - * - * Authors: Jan Safranek - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "tools-common.h" - -static struct option const long_options[] = -{ - {"recursive", no_argument, NULL, 'r'}, - {"help", no_argument, NULL, 'h'}, - {"group", required_argument, NULL, 'g'}, - {NULL, 0, NULL, 0} -}; - -struct ext_cgroup_record { - char name[FILENAME_MAX]; /* controller name */ - char controller[FILENAME_MAX]; /* cgroup name */ - int h_number; /* hierarchy number */ -}; - - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s --help' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-h] [-r] [[-g] :] ...\n", - program_name); - printf("Remove control group(s)\n"); - printf(" -g : Control group to be removed "\ - "(-g is optional)\n"); - printf(" -h, --help Display this help\n"); - printf(" -r, --recursive Recursively remove "\ - "all subgroups\n"); -} - -/* - * Skip adding controller which points to the same cgroup when delete - * cgroup with specifying multi controllers. Just skip controller which - * cgroup and hierarchy number is same - */ -static int skip_add_controller(int counter, int *skip, - struct ext_cgroup_record *ecg_list) -{ - int k; - struct controller_data info; - void *handle; - int ret = 0; - - /* find out hierarchy number of added cgroup */ - ecg_list[counter].h_number = 0; - ret = cgroup_get_all_controller_begin(&handle, &info); - while (ret == 0) { - if (!strcmp(info.name, ecg_list[counter].name)) { - /* hierarchy number found out, set it */ - ecg_list[counter].h_number = info.hierarchy; - break; - } - ret = cgroup_get_all_controller_next(&handle, &info); - } - cgroup_get_all_controller_end(&handle); - - /* deal with cgroup_get_controller_begin/next ret values */ - if (ret == ECGEOF) - ret = 0; - if (ret) { - fprintf(stderr, "cgroup_get_controller_begin/next failed(%s)\n", - cgroup_strerror(ret)); - return ret; - } - - /* found out whether the hierarchy should be skipped */ - *skip = 0; - for (k = 0; k < counter; k++) { - if ((!strcmp(ecg_list[k].name, ecg_list[counter].name)) && - (ecg_list[k].h_number == ecg_list[counter].h_number)) { - /* we found a control group in the same hierarchy */ - if (strcmp(ecg_list[k].controller, - ecg_list[counter].controller)) { - /* - * it is a different controller -> - * if there is not one cgroup for the same - * controller, skip it - */ - *skip = 1; - } else { - /* - * there is the identical group,controller pair - * don't skip it - */ - *skip = 0; - return ret; - } - } - } - - return ret; -} - - -int main(int argc, char *argv[]) -{ - int ret = 0; - int i, j; - int c; - int flags = 0; - int final_ret = 0; - - int counter = 0; - int max = 0; - struct ext_cgroup_record *ecg_list = NULL; - int skip; - - struct cgroup_group_spec **cgroup_list = NULL; - struct cgroup *cgroup; - struct cgroup_controller *cgc; - - /* initialize libcg */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "%s: " - "libcgroup initialization failed: %s\n", - argv[0], cgroup_strerror(ret)); - goto err; - } - - cgroup_list = calloc(argc, sizeof(struct cgroup_group_spec *)); - if (cgroup_list == NULL) { - fprintf(stderr, "%s: out of memory\n", argv[0]); - ret = -1; - goto err; - } - - ecg_list = calloc(argc, sizeof(struct ext_cgroup_record *)); - if (cgroup_list == NULL) { - fprintf(stderr, "%s: out of memory\n", argv[0]); - ret = -1; - goto err; - } - - /* - * Parse arguments - */ - while ((c = getopt_long(argc, argv, "rhg:", - long_options, NULL)) > 0) { - switch (c) { - case 'r': - flags |= CGFLAG_DELETE_RECURSIVE; - break; - case 'g': - ret = parse_cgroup_spec(cgroup_list, optarg, argc); - if (ret != 0) { - fprintf(stderr, - "%s: error parsing cgroup '%s'\n", - argv[0], optarg); - ret = -1; - goto err; - } - break; - case 'h': - usage(0, argv[0]); - ret = 0; - goto err; - default: - usage(1, argv[0]); - ret = -1; - goto err; - } - } - - /* parse groups on command line */ - for (i = optind; i < argc; i++) { - ret = parse_cgroup_spec(cgroup_list, argv[i], argc); - if (ret != 0) { - fprintf(stderr, "%s: error parsing cgroup '%s'\n", - argv[0], argv[i]); - ret = -1; - goto err; - } - } - - /* for each cgroup to be deleted */ - for (i = 0; i < argc; i++) { - if (!cgroup_list[i]) - break; - - /* create the new cgroup structure */ - cgroup = cgroup_new_cgroup(cgroup_list[i]->path); - if (!cgroup) { - ret = ECGFAIL; - fprintf(stderr, "%s: can't create new cgroup: %s\n", - argv[0], cgroup_strerror(ret)); - goto err; - } - - /* add controllers to the cgroup */ - j = 0; - while (cgroup_list[i]->controllers[j]) { - skip = 0; - /* - * save controller name, cg name and hierarchy number - * to determine whether we should skip adding controller - */ - if (counter == max) { - /* - * there is not enough space to store them, - * create it - */ - max = max + argc; - ecg_list = (struct ext_cgroup_record *) - realloc(ecg_list, - max * sizeof(struct ext_cgroup_record)); - if (!ecg_list) { - fprintf(stderr, "%s: ", argv[0]); - fprintf(stderr, "not enough memory\n"); - final_ret = -1; - goto err; - } - } - - strncpy(ecg_list[counter].controller, - cgroup_list[i]->controllers[j], FILENAME_MAX); - ecg_list[counter].controller[FILENAME_MAX - 1] = '\0'; - strncpy(ecg_list[counter].name, - cgroup_list[i]->path, FILENAME_MAX); - ecg_list[counter].name[FILENAME_MAX - 1] = '\0'; - - ret = skip_add_controller(counter, &skip, ecg_list); - if (ret) - goto err; - - if (skip) { - /* don't add the controller, goto next one */ - goto next; - } - - cgc = cgroup_add_controller(cgroup, - cgroup_list[i]->controllers[j]); - if (!cgc) { - ret = ECGFAIL; - fprintf(stderr, "%s: " - "controller %s can't be added\n", - argv[0], - cgroup_list[i]->controllers[j]); - cgroup_free(&cgroup); - goto err; - } -next: - counter++; - j++; - } - - ret = cgroup_delete_cgroup_ext(cgroup, flags); - /* - * Remember the errors and continue, try to remove all groups. - */ - if (ret != 0) { - fprintf(stderr, "%s: cannot remove group '%s': %s\n", - argv[0], cgroup->name, - cgroup_strerror(ret)); - final_ret = ret; - } - cgroup_free(&cgroup); - } - - ret = final_ret; -err: - if (ecg_list) - free(ecg_list); - - if (cgroup_list) { - for (i = 0; i < argc; i++) { - if (cgroup_list[i]) - cgroup_free_group_spec(cgroup_list[i]); - } - free(cgroup_list); - } - return ret; -} diff --git a/src/tools/cgexec.c b/src/tools/cgexec.c deleted file mode 100644 index d0874537..00000000 --- a/src/tools/cgexec.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright RedHat Inc. 2008 - * - * Authors: Vivek Goyal - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tools-common.h" - -static struct option longopts[] = { - {"sticky", no_argument, NULL, 's'}, - {"help", no_argument, NULL, 'h'}, - {0, 0, 0, 0} -}; - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s --help' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-h] [-g :] [--sticky] "\ - "command [arguments] ...\n", program_name); - printf("Run the task in given control group(s)\n"); - printf(" -g : Control group which "\ - "should be added\n"); - printf(" -h, --help Display this help\n"); - printf(" --sticky cgred daemon does not "\ - "change pidlist and children tasks\n"); -} - - -int main(int argc, char *argv[]) -{ - int ret = 0, i; - int cg_specified = 0; - int flag_child = 0; - uid_t uid; - gid_t gid; - pid_t pid; - int c; - struct cgroup_group_spec *cgroup_list[CG_HIER_MAX]; - - memset(cgroup_list, 0, sizeof(cgroup_list)); - - while ((c = getopt_long(argc, argv, "+g:sh", longopts, NULL)) > 0) { - switch (c) { - case 'g': - ret = parse_cgroup_spec(cgroup_list, optarg, - CG_HIER_MAX); - if (ret) { - fprintf(stderr, "cgroup controller and path" - "parsing failed\n"); - return -1; - } - cg_specified = 1; - break; - case 's': - flag_child |= CGROUP_DAEMON_UNCHANGE_CHILDREN; - break; - case 'h': - usage(0, argv[0]); - exit(0); - default: - usage(1, argv[0]); - exit(1); - } - } - - /* Executable name */ - if (!argv[optind]) { - usage(1, argv[0]); - exit(1); - } - - /* Initialize libcg */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "libcgroup initialization failed: %s\n", - cgroup_strerror(ret)); - return ret; - } - - /* Just for debugging purposes. */ - uid = geteuid(); - gid = getegid(); - cgroup_dbg("My euid and egid is: %d,%d\n", (int) uid, (int) gid); - - uid = getuid(); - gid = getgid(); - pid = getpid(); - - ret = cgroup_register_unchanged_process(pid, flag_child); - if (ret) { - fprintf(stderr, "registration of process failed\n"); - return ret; - } - - /* - * 'cgexec' command file needs the root privilege for executing - * a cgroup_register_unchanged_process() by using unix domain - * socket, and an euid/egid should be changed to the executing user - * from a root user. - */ - if (setresuid(uid, uid, uid)) { - fprintf(stderr, "%s", strerror(errno)); - return -1; - } - if (setresgid(gid, gid, gid)) { - fprintf(stderr, "%s", strerror(errno)); - return -1; - } - if (cg_specified) { - /* - * User has specified the list of control group and - * controllers - * */ - for (i = 0; i < CG_HIER_MAX; i++) { - if (!cgroup_list[i]) - break; - - ret = cgroup_change_cgroup_path(cgroup_list[i]->path, - pid, - (const char*const*) cgroup_list[i]->controllers); - if (ret) { - fprintf(stderr, - "cgroup change of group failed\n"); - return ret; - } - } - } else { - - /* Change the cgroup by determining the rules based on uid */ - ret = cgroup_change_cgroup_flags(uid, gid, - argv[optind], pid, 0); - if (ret) { - fprintf(stderr, "cgroup change of group failed\n"); - return ret; - } - } - - /* Now exec the new process */ - ret = execvp(argv[optind], &argv[optind]); - if (ret == -1) { - fprintf(stderr, "%s", strerror(errno)); - return -1; - } - return 0; -} diff --git a/src/tools/cgget.c b/src/tools/cgget.c deleted file mode 100644 index 4764f143..00000000 --- a/src/tools/cgget.c +++ /dev/null @@ -1,466 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -#include "tools-common.h" - -#define MODE_SHOW_HEADERS 1 -#define MODE_SHOW_NAMES 2 -#define MODE_SHOW_ALL_CONTROLLERS 4 - -#define LL_MAX 100 - -static struct option const long_options[] = -{ - {"variable", required_argument, NULL, 'r'}, - {"help", no_argument, NULL, 'h'}, - {"all", no_argument, NULL, 'a'}, - {"values-only", no_argument, NULL, 'v'}, - {NULL, 0, NULL, 0} -}; - -enum group{ - GR_NOTSET = 0, /* 0 .. path not specified -g or -a not used */ - GR_GROUP, /* 1 .. path not specified -g or -a used */ - GR_LIST /* 2 .. path specified using -g:

*/ -}; - - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-nv] [-r ] [-g ] "\ - "[-a] ...\n"\ - " or: %s [-nv] [-r ] -g : ...\n", - program_name, program_name); - printf("Print parameter(s) of given group(s).\n"); - printf(" -a, --all Print info about all relevant "\ - "controllers\n"); - printf(" -g Controller which info should "\ - "be displayed\n"); - printf(" -g : Control group which info "\ - "should be displayed\n"); - printf(" -h, --help Display this help\n"); - printf(" -n Do not print headers\n"); - printf(" -r, --variable Define parameter to display\n"); - printf(" -v, --values-only Print only values, not "\ - "parameter names\n"); -} - -static int display_record(char *name, - struct cgroup_controller *group_controller, - const char *group_name, const char *program_name, int mode) -{ - int ret = 0; - void *handle; - char line[LL_MAX]; - int ind = 0; - - if (mode & MODE_SHOW_NAMES) - printf("%s: ", name); - - /* start the reading of the variable value */ - ret = cgroup_read_value_begin(group_controller->name, - group_name, name, &handle, line, LL_MAX); - - if (ret == ECGEOF) { - printf("\n"); - goto read_end; - } - - if (ret != 0) - goto end; - - printf("%s", line); - if (line[strlen(line)-1] == '\n') - /* if value continue on the next row. indent it */ - ind = 1; - - - /* read iteratively the whole value */ - while ((ret = cgroup_read_value_next(&handle, line, LL_MAX)) == 0) { - if (ind == 1) - printf("\t"); - printf("%s", line); - ind = 0; - - /* if value continue on the next row. indent it */ - if (line[strlen(line)-1] == '\n') - ind = 1; - } - -read_end: - cgroup_read_value_end(&handle); - if (ret == ECGEOF) - ret = 0; - -end: - if (ret != 0) - fprintf(stderr, "variable file read failed %s\n", - cgroup_strerror(ret)); - return ret; -} - - - -static int display_name_values(char **names, const char* group_name, - const char *program_name, int mode) -{ - int i; - struct cgroup_controller *group_controller = NULL; - struct cgroup *group = NULL; - int ret = 0; - char *controller = NULL, *dot; - - group = cgroup_new_cgroup(group_name); - if (group == NULL) { - fprintf(stderr, "%s: cannot create group '%s'\n", program_name, - group_name); - return -1; - } - ret = cgroup_get_cgroup(group); - if (ret != 0) { - fprintf(stderr, "%s: cannot read group '%s': %s\n", - program_name, group_name, cgroup_strerror(ret)); - goto err; - } - - i = 0; - while (names[i] != NULL) { - /* Parse the controller out of 'controller.parameter'. */ - free(controller); - controller = strdup(names[i]); - if (controller == NULL) { - fprintf(stderr, "%s: out of memory\n", program_name); - ret = -1; - goto err; - } - dot = strchr(controller, '.'); - if (dot == NULL) { - fprintf(stderr, "%s: error parsing parameter name\n" \ - " '%s'", program_name, names[i]); - ret = -1; - goto err; - } - *dot = '\0'; - - /* Find appropriate controller. */ - group_controller = cgroup_get_controller(group, controller); - if (group_controller == NULL) { - fprintf(stderr, "%s: cannot find controller " \ - "'%s' in group '%s'\n", program_name, - controller, group_name); - ret = -1; - goto err; - } - - /* Finally read the parameter value.*/ - ret = display_record(names[i], group_controller, - group_name, program_name, mode); - if (ret != 0) - goto err; - i++; - } -err: - if (controller) - free(controller); - if (group) - cgroup_free(&group); - return ret; -} - -static int display_controller_values(char **controllers, const char *group_name, - const char *program_name, int mode) -{ - struct cgroup *group = NULL; - struct cgroup_controller *group_controller = NULL; - char *name; - int i, j; - int name_count; - int ret = 0; - int result = 0; - - /* initialize group_name variable */ - group = cgroup_new_cgroup(group_name); - if (group == NULL) { - fprintf(stderr, "%s:cannot create group '%s'\n", - program_name, group_name); - return -1; - } - - ret = cgroup_get_cgroup(group); - if (ret != 0) { - if (!(mode & MODE_SHOW_ALL_CONTROLLERS)) - fprintf(stderr, "%s: cannot read group '%s': %s\n", - program_name, group_name, cgroup_strerror(ret)); - } - - /* for all wanted controllers */ - j = 0; - while (controllers[j] != NULL) { - /* read the controller group data */ - group_controller = cgroup_get_controller(group, controllers[j]); - if (group_controller == NULL) { - if (!(mode & MODE_SHOW_ALL_CONTROLLERS)) { - fprintf(stderr, "%s: cannot find controller "\ - "'%s' in group '%s'\n", program_name, - controllers[j], group_name); - result = -1; - } - } - - /* for each variable of given group print the statistic */ - name_count = cgroup_get_value_name_count(group_controller); - for (i = 0; i < name_count; i++) { - name = cgroup_get_value_name(group_controller, i); - if (name != NULL) { - ret = display_record(name, group_controller, - group_name, program_name, mode); - if (ret) { - result = ret; - goto err; - } - } - } - j = j+1; - } - -err: - cgroup_free(&group); - return result; - -} - -static int display_values(char **controllers, int max, const char *group_name, - char **names, int mode, const char *program_name) -{ - int ret, result = 0; - - /* display the directory if needed */ - if (mode & MODE_SHOW_HEADERS) - printf("%s:\n", group_name); - - /* display all wanted variables */ - if (names[0] != NULL) { - ret = display_name_values(names, group_name, program_name, - mode); - if (ret) - result = ret; - } - - /* display all wanted controllers */ - if (controllers[0] != NULL) { - ret = display_controller_values(controllers, group_name, - program_name, mode); - if (ret) - result = ret; - } - - /* separate each group with empty line. */ - if (mode & MODE_SHOW_HEADERS) - printf("\n"); - - return result; -} - -int add_record_to_buffer(char **buffer, char *record, int capacity) -{ - int i; - - /* find first free entry inside the cgroup data array */ - for (i = 0; i < capacity; i++) { - if (!buffer[i]) - break; - } - - if (i < capacity) { - buffer[i] = strdup(record); - if (buffer[i] == NULL) - return 1; - return 0; - } - return 1; -} - - -int main(int argc, char *argv[]) -{ - int ret = 0; - int result = 0; - int c, i; - int group_needed = GR_NOTSET; - - int capacity = argc + CG_CONTROLLER_MAX; /* maximal number of records */ - struct cgroup_group_spec **cgroup_list; /* list of all groups */ - char **names; /* list of wanted variable names */ - char **controllers; /* list of wanted controllers*/ - - void *handle; - struct cgroup_mount_point controller; - - int mode = MODE_SHOW_NAMES | MODE_SHOW_HEADERS; - - /* No parameter on input? */ - if (argc < 2) { - usage(1, argv[0]); - return 1; - } - - names = (char **)calloc(capacity+1, sizeof(char *)); - controllers = (char **)calloc(capacity+1, sizeof(char *)); - cgroup_list = (struct cgroup_group_spec **)calloc(capacity, - sizeof(struct cgroup_group_spec *)); - if ((names == NULL) || (controllers == NULL) || - (cgroup_list == NULL)) { - fprintf(stderr, "%s: out of memory\n", argv[0]); - ret = -1; - goto err_free; - } - - /* Parse arguments. */ - while ((c = getopt_long(argc, argv, "r:hnvg:a", long_options, NULL)) - > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - result = 0; - goto err; - break; - - case 'n': - /* Do not show headers. */ - mode = mode & (INT_MAX ^ MODE_SHOW_HEADERS); - break; - - case 'v': - /* Do not show parameter names. */ - mode = mode & (INT_MAX ^ MODE_SHOW_NAMES); - break; - - case 'r': - /* Add name to buffer. */ - ret = add_record_to_buffer(names, optarg, capacity); - if (ret) { - result = ret; - goto err; - } - break; - case 'g': - if (strchr(optarg, ':') == NULL) { - /* -g */ - if (group_needed == GR_LIST) { - usage(1, argv[0]); - result = -1; - goto err; - } - group_needed = GR_GROUP; - add_record_to_buffer(controllers, optarg, - capacity); - } else { - /* -g : */ - if (group_needed == GR_GROUP) { - usage(1, argv[0]); - result = -1; - goto err; - } - group_needed = GR_LIST; - ret = parse_cgroup_spec(cgroup_list, optarg, - capacity); - if (ret) { - fprintf(stderr, "%s: cgroup controller/" - "path parsing failed (%s)\n", - argv[0], argv[optind]); - ret = -1; - goto err; - } - } - break; - case 'a': - if (group_needed == GR_LIST) { - usage(1, argv[0]); - result = -1; - goto err; - } - group_needed = GR_GROUP; - /* go through cgroups for all possible controllers */ - mode |= MODE_SHOW_ALL_CONTROLLERS; - break; - default: - usage(1, argv[0]); - result = -1; - goto err; - } - } - - if (((group_needed == GR_LIST) && (argv[optind])) || - ((group_needed != GR_LIST) && (!argv[optind]))) { - /* mixed -g : and or path not set */ - usage(1, argv[0]); - result = -1; - goto err; - } - - /* Initialize libcgroup. */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "%s: libcgroup initialization failed: %s\n", - argv[0], cgroup_strerror(ret)); - result = ret; - goto err; - } - - if ((mode & MODE_SHOW_ALL_CONTROLLERS) || - ((controllers[0] == NULL) && (names[0] == NULL) - && (cgroup_list[0] == NULL))) { - /* show info about all controllers */ - ret = cgroup_get_controller_begin(&handle, &controller); - /* go through list of controllers, add them to the list */ - while (ret == 0) { - add_record_to_buffer(controllers, controller.name, - capacity); - ret = cgroup_get_controller_next(&handle, &controller); - } - cgroup_get_controller_end(&handle); - } - - /* Parse control groups set by -g:

pairs */ - for (i = 0; i < capacity; i++) { - if (!cgroup_list[i]) - break; - ret |= display_values(cgroup_list[i]->controllers, capacity, - cgroup_list[i]->path, names, mode, argv[0]); - } - - /* Parse control groups and print them .*/ - for (i = optind; i < argc; i++) { - ret |= display_values(controllers, capacity, - argv[i], names, mode, argv[0]); - } - -err: - for (i = 0; i < capacity; i++) { - if (cgroup_list[i]) - cgroup_free_group_spec(cgroup_list[i]); - if (controllers[i]) - free(controllers[i]); - if (names[i]) - free(names[i]); - } - -err_free: - free(cgroup_list); - free(controllers); - free(names); - - return result; -} diff --git a/src/tools/cgset.c b/src/tools/cgset.c deleted file mode 100644 index ddaeac43..00000000 --- a/src/tools/cgset.c +++ /dev/null @@ -1,251 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -#include "tools-common.h" - -#define FL_RULES 1 -#define FL_COPY 2 - -enum { - COPY_FROM_OPTION = CHAR_MAX + 1 -}; - -static struct option const long_options[] = -{ - {"rule", required_argument, NULL, 'r'}, - {"help", no_argument, NULL, 'h'}, - {"copy-from", required_argument, NULL, COPY_FROM_OPTION}, - {NULL, 0, NULL, 0} -}; - -int flags; /* used input method */ - -static struct cgroup *copy_name_value_from_cgroup(char src_cg_path[FILENAME_MAX]) -{ - int ret = 0; - struct cgroup *src_cgroup; - - /* create source cgroup */ - src_cgroup = cgroup_new_cgroup(src_cg_path); - if (!src_cgroup) { - fprintf(stderr, "can't create cgroup: %s\n", - cgroup_strerror(ECGFAIL)); - goto scgroup_err; - } - - /* copy the name-version values to the cgroup structure */ - ret = cgroup_get_cgroup(src_cgroup); - if (ret != 0) { - fprintf(stderr, "cgroup %s error: %s \n", - src_cg_path, cgroup_strerror(ret)); - goto scgroup_err; - } - - return src_cgroup; - -scgroup_err: - cgroup_free(&src_cgroup); - return NULL; -} - - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s --help' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-r ] ...\n" - " or: %s --copy-from "\ - " ...\n", program_name, program_name); - printf("Set the parameters of given cgroup(s)\n"); - printf(" -r, --variable Define parameter "\ - "to set\n"); - printf(" --copy-from Control group whose "\ - "parameters will be copied\n"); -} - -int main(int argc, char *argv[]) -{ - int ret = 0; - int c; - - char *buf; - struct control_value *name_value = NULL; - int nv_number = 0; - int nv_max = 0; - - char src_cg_path[FILENAME_MAX]; - struct cgroup *src_cgroup; - struct cgroup *cgroup; - - /* no parametr on input */ - if (argc < 2) { - fprintf(stderr, "Usage is %s -r " - "\n", argv[0]); - return -1; - } - - /* parse arguments */ - while ((c = getopt_long (argc, argv, - "r:h", long_options, NULL)) != -1) { - switch (c) { - case 'h': - usage(0, argv[0]); - ret = 0; - goto err; - break; - - case 'r': - if ((flags & FL_COPY) != 0) { - usage(1, argv[0]); - ret = -1; - goto err; - } - flags |= FL_RULES; - - /* add name-value pair to buffer - (= name_value variable) */ - if (nv_number >= nv_max) { - nv_max += CG_NV_MAX; - name_value = (struct control_value *) - realloc(name_value, - nv_max * sizeof(struct control_value)); - if (!name_value) { - fprintf(stderr, "%s: " - "not enough memory\n", - argv[0]); - ret = -1; - goto err; - } - } - - /* parse optarg value */ - /* there is necessary to input the tuple n=v */ - buf = strtok(optarg, "="); - if (buf == NULL) { - fprintf(stderr, "%s: " - "wrong parameter of option -r: %s\n", - argv[0], optarg); - ret = -1; - goto err; - } - - strncpy(name_value[nv_number].name, buf, FILENAME_MAX); - name_value[nv_number].name[FILENAME_MAX-1] = '\0'; - - buf = strtok(NULL, "="); - if (buf == NULL) { - fprintf(stderr, "%s: " - "wrong parameter of option -r: %s\n", - argv[0], optarg); - ret = -1; - goto err; - } - - strncpy(name_value[nv_number].value, buf, CG_CONTROL_VALUE_MAX); - name_value[nv_number].value[CG_CONTROL_VALUE_MAX-1] = '\0'; - - nv_number++; - break; - case COPY_FROM_OPTION: - if (flags != 0) { - usage(1, argv[0]); - ret = -1; - goto err; - } - flags |= FL_COPY; - strncpy(src_cg_path, optarg, FILENAME_MAX); - src_cg_path[FILENAME_MAX-1] = '\0'; - break; - default: - usage(1, argv[0]); - ret = -1; - goto err; - break; - } - } - - /* no cgroup name */ - if (!argv[optind]) { - fprintf(stderr, "%s: no cgroup specified\n", argv[0]); - ret = -1; - goto err; - } - - if (flags == 0) { - fprintf(stderr, "%s: no name-value pair was set\n", argv[0]); - ret = -1; - goto err; - } - - /* initialize libcgroup */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "%s: libcgroup initialization failed: %s\n", - argv[0], cgroup_strerror(ret)); - goto err; - } - - /* copy the name-value pairs from -r options */ - if ((flags & FL_RULES) != 0) { - src_cgroup = create_cgroup_from_name_value_pairs( - "tmp", name_value, nv_number); - if (src_cgroup == NULL) - goto err; - } - - /* copy the name-value from the given group */ - if ((flags & FL_COPY) != 0) { - src_cgroup = copy_name_value_from_cgroup(src_cg_path); - if (src_cgroup == NULL) - goto err; - } - - while (optind < argc) { - /* create new cgroup */ - cgroup = cgroup_new_cgroup(argv[optind]); - if (!cgroup) { - ret = ECGFAIL; - fprintf(stderr, "%s: can't add new cgroup: %s\n", - argv[0], cgroup_strerror(ret)); - goto cgroup_free_err; - } - - /* copy the values from the source cgroup to new one */ - ret = cgroup_copy_cgroup(cgroup, src_cgroup); - if (ret != 0) { - fprintf(stderr, "%s: cgroup %s error: %s \n", - argv[0], src_cg_path, cgroup_strerror(ret)); - goto cgroup_free_err; - } - - /* modify cgroup based on values of the new one */ - ret = cgroup_modify_cgroup(cgroup); - if (ret) { - fprintf(stderr, "%s: cgroup modify error: %s \n", - argv[0], cgroup_strerror(ret)); - goto cgroup_free_err; - } - - optind++; - cgroup_free(&cgroup); - } - -cgroup_free_err: - if (cgroup) - cgroup_free(&cgroup); - cgroup_free(&src_cgroup); - -err: - free(name_value); - return ret; -} diff --git a/src/tools/cgsnapshot.c b/src/tools/cgsnapshot.c deleted file mode 100644 index 66e3bbca..00000000 --- a/src/tools/cgsnapshot.c +++ /dev/null @@ -1,843 +0,0 @@ -/* " Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. - * " Written by Ivana Hutarova Varekova - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -enum flag{ - FL_LIST = 1, - FL_SILENT = 2, /* do-not show any warning/error output */ - FL_STRICT = 4, /* don show the variables which are not on - whitelist */ - FL_OUTPUT = 8, /* output should be redirect to the given file */ - FL_BLACK = 16, /* blacklist set */ - FL_WHITE = 32, /* whitelist set */ -}; - -#define BLACKLIST_CONF "/etc/cgsnapshot_blacklist.conf" -#define WHITELIST_CONF "/etc/cgsnapshot_whitelist.conf" - -struct black_list_type { - char *name; /* variable name */ - struct black_list_type *next; /* pointer to the next record */ -}; - -struct black_list_type *black_list; -struct black_list_type *white_list; - -typedef char cont_name_t[FILENAME_MAX]; - -int flags; -FILE *of; - -/* - * Display the usage - */ -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-h] [-s] [-b FILE] [-w FILE] [-f FILE] "\ - "[controller] [...]\n", program_name); - printf("Generate the configuration file for given controllers\n"); - printf(" -b, --blacklist=FILE Set the blacklist"\ - " configuration file (default %s)\n", BLACKLIST_CONF); - printf(" -f, --file=FILE Redirect the output"\ - " to output_file\n"); - printf(" -h, --help Display this help\n"); - printf(" -s, --silent Ignore all warnings\n"); - printf(" -t, --strict Don't show variables "\ - "which are not on the whitelist\n"); - printf(" -w, --whitelist=FILE Set the whitelist"\ - " configuration file (don't used by default)\n"); -} - -/* cache values from blacklist file to the list structure */ - -int load_list(char *filename, struct black_list_type **p_list) -{ - FILE *fw; - int i = 0; - int ret; - char buf[FILENAME_MAX]; - char name[FILENAME_MAX]; - - struct black_list_type *start = NULL; - struct black_list_type *end = NULL; - struct black_list_type *new; - - fw = fopen(filename, "r"); - if (fw == NULL) { - fprintf(stderr, "ERROR: Failed to open file %s: %s\n", - filename, strerror(errno)); - *p_list = NULL; - return 1; - } - - /* go through the configuration file and search the line */ - while (fgets(buf, FILENAME_MAX, fw) != NULL) { - buf[FILENAME_MAX-1] = '\0'; - i = 0; - - /* if the record start with # then skip it */ - while ((buf[i] == ' ') || (buf[i] == '\n')) - i++; - - if ((buf[i] == '#') || (buf[i] == '\0')) - continue; - - ret = sscanf(buf, "%s", name); - if (ret == 0) - continue; - - new = (struct black_list_type *)malloc(sizeof - (struct black_list_type)); - if (new == NULL) { - fprintf(stderr, "ERROR: Memory allocation problem " - "(%s)\n", strerror(errno)); - ret = 1; - goto err; - } - - new->name = strdup(name); - if (new->name == NULL) { - fprintf(stderr, "ERROR: Memory allocation problem " - "(%s)\n", strerror(errno)); - ret = 1; - free(new); - goto err; - } - new->next = NULL; - - /* update the variables list */ - if (start == NULL) { - start = new; - end = new; - } else { - end->next = new; - end = new; - } - } - - fclose(fw); - - *p_list = start; - return 0; - -err: - fclose(fw); - new = start; - while (new != NULL) { - end = new->next; - free(new->name); - free(new); - new = end; - } - *p_list = NULL; - return ret; -} - -/* free list structure */ -void free_list(struct black_list_type *list) -{ - struct black_list_type *now; - struct black_list_type *next; - - now = list; - while (now != NULL) { - next = now->next; - free(now->name); - free(now); - now = next; - } - return; -} - -/* Test whether the variable is on the list - * return values are: - * 1 ... was found - * 0 ... no record was found - */ -int is_on_list(char *name, struct black_list_type *list) -{ - struct black_list_type *record; - - record = list; - /* go through the list of all values */ - while (record != NULL) { - /* if the variable name is found */ - if (strcmp(record->name, name) == 0) { - /* return its value */ - return 1; - } - record = record->next; - } - - /* the variable was not found */ - return 0; - -} - -/* Display permissions record for the given group - * defined by path - */ -static int display_permissions(const char *path, - const char *program_name) -{ - int ret; - struct stat sba; - struct stat sbt; - struct passwd *pw; - struct group *gr; - char tasks_path[FILENAME_MAX]; - - /* admin permissions record */ - /* get the directory statistic */ - ret = stat(path, &sba); - if (ret) { - fprintf(stderr, "ERROR: can't read statistics about %s\n", - path); - return -1; - } - - /* tasks permissions record */ - /* get tasks file statistic */ - strncpy(tasks_path, path, FILENAME_MAX); - tasks_path[FILENAME_MAX-1] = '\0'; - strncat(tasks_path, "/tasks", FILENAME_MAX - strlen(tasks_path) - 1); - tasks_path[FILENAME_MAX-1] = '\0'; - ret = stat(tasks_path, &sbt); - if (ret) { - fprintf(stderr, "ERROR: can't read statistics about %s\n", - tasks_path); - return -1; - } - - if ((sba.st_uid) || (sba.st_gid) || - (sbt.st_uid) || (sbt.st_gid)) { - /* some uid or gid is nonroot, admin permission - tag is necessery */ - - /* print the header */ - fprintf(of, "\tperm {\n"); - - /* find out the user and group name */ - pw = getpwuid(sba.st_uid); - if (pw == NULL) { - fprintf(stderr, "ERROR: can't get %d user name\n", - sba.st_uid); - return -1; - } - - gr = getgrgid(sba.st_gid); - if (gr == NULL) { - fprintf(stderr, "ERROR: can't get %d group name\n", - sba.st_gid); - return -1; - } - - /* print the admin record */ - fprintf(of, "\t\tadmin {\n"\ - "\t\t\tuid = %s;\n"\ - "\t\t\tgid = %s;\n"\ - "\t\t}\n", pw->pw_name, gr->gr_name); - - /* find out the user and group name */ - pw = getpwuid(sbt.st_uid); - if (pw == NULL) { - fprintf(stderr, "ERROR: can't get %d user name\n", - sbt.st_uid); - return -1; - } - - gr = getgrgid(sbt.st_gid); - if (gr == NULL) { - fprintf(stderr, "ERROR: can't get %d group name\n", - sbt.st_gid); - return -1; - } - - /* print the task record */ - fprintf(of, "\t\ttask {\n"\ - "\t\t\tuid = %s;\n"\ - "\t\t\tgid = %s;\n"\ - "\t\t}\n", pw->pw_name, gr->gr_name); - - fprintf(of, "\t}\n"); - } - - return 0; -} - -/* Displey the control group record: - * header - * permission record - * controllers records - * tail - */ - -static int display_cgroup_data(struct cgroup *group, - char controller[CG_CONTROLLER_MAX][FILENAME_MAX], - const char *group_path, int root_path_len, int first, - const char *program_name) -{ - int i = 0, j; - int bl, wl = 0; /* is on the blacklist/whitelist flag */ - int nr_var = 0; - char *name; - char *output_name; - struct cgroup_controller *group_controller = NULL; - char *value = NULL; - char var_path[FILENAME_MAX]; - int ret = 0; - struct stat sb; - - /* print the group definition header */ - fprintf(of, "group %s {\n", group->name); - - /* display the permission tags */ - ret = display_permissions(group_path, program_name); - if (ret) - return ret; - - /* for all wanted controllers display controllers tag */ - while (controller[i][0] != '\0') { - - group_controller = cgroup_get_controller(group, controller[i]); - if (group_controller == NULL) { - printf("cannot find controller "\ - "'%s' in group '%s'\n", - controller[i], group->name); - i++; - ret = -1; - continue; - } - - /* print the controller header */ - if (strncmp(controller[i], "name=", 5) == 0) - fprintf(of, "\t\"%s\" {\n", controller[i]); - else - fprintf(of, "\t%s {\n", controller[i]); - i++; - nr_var = cgroup_get_value_name_count(group_controller); - - for (j = 0; j < nr_var; j++) { - name = cgroup_get_value_name(group_controller, j); - - /* For the non-root groups cgconfigparser set - permissions of variable files to 777. Thus - It is necessary to test the permissions of - variable files in the root group to find out - whether the variable is writable. - */ - if (root_path_len >= FILENAME_MAX) - root_path_len = FILENAME_MAX - 1; - strncpy(var_path, group_path, root_path_len); - var_path[root_path_len] = '\0'; - strncat(var_path, "/", FILENAME_MAX - - strlen(var_path) - 1); - var_path[FILENAME_MAX-1] = '\0'; - strncat(var_path, name, FILENAME_MAX - - strlen(var_path) - 1); - var_path[FILENAME_MAX-1] = '\0'; - - /* test whether the write permissions */ - ret = stat(var_path, &sb); - /* freezer.state is not in root group so ret != 0, - * but it should be listed - * device.list should be read to create - * device.allow input - */ - if ((ret == 0) && ((sb.st_mode & S_IWUSR) == 0) && - (strcmp("devices.list", name) != 0)) { - /* variable is not writable */ - continue; - } - - /* find whether the variable is blacklisted or - whitelisted */ - bl = is_on_list(name, black_list); - wl = is_on_list(name, white_list); - - /* if it is blacklisted skip it and continue */ - if (bl) - continue; - - /* if it is not whitelisted and strict tag is used - skip it and continue too */ - if ((!wl) && (flags & FL_STRICT)) - continue; - - /* if it is not whitelisted and silent tag is not - used write an warning */ - if ((!wl) && !(flags & FL_SILENT) && (first)) - fprintf(stderr, "WARNING: variable %s is "\ - "neither blacklisted nor "\ - "whitelisted\n", name); - - output_name = name; - - /* deal with devices variables: - * - omit devices.deny and device.allow, - * - generate devices.{deny,allow} from - * device.list variable (deny all and then - * all device.list devices */ - if ((strcmp("devices.deny", name) == 0) || - (strcmp("devices.allow", name) == 0)) { - continue; - } - if (strcmp("devices.list", name) == 0) { - output_name = "devices.allow"; - fprintf(of, - "\t\tdevices.deny=\"a *:* rwm\";\n"); - } - - ret = cgroup_get_value_string(group_controller, - name, &value); - - /* variable can not be read */ - if (ret != 0) { - ret = 0; - fprintf(stderr, "ERROR: Value of "\ - "variable %s can be read\n", - name); - goto err; - } - fprintf(of, "\t\t%s=\"%s\";\n", output_name, value); - free(value); - } - fprintf(of, "\t}\n"); - } - - /* tail of the record */ - fprintf(of, "}\n\n"); - -err: - return ret; -} - -/* - * creates the record about the hierarchie which contains - * "controller" subsystem - */ -static int display_controller_data( - char controller[CG_CONTROLLER_MAX][FILENAME_MAX], - const char *program_name) -{ - int ret; - void *handle; - int first = 1; - - struct cgroup_file_info info; - int lvl; - - int prefix_len; - char cgroup_name[FILENAME_MAX]; - - struct cgroup *group = NULL; - - /* start to parse the structure for the first controller - - controller[0] attached to hierarchie */ - ret = cgroup_walk_tree_begin(controller[0], "/", 0, - &handle, &info, &lvl); - if (ret != 0) - return ret; - - prefix_len = strlen(info.full_path); - - /* go through all files and directories */ - while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) == 0) { - /* some group starts here */ - if (info.type == CGROUP_FILE_TYPE_DIR) { - /* parse the group name from full_path*/ - strncpy(cgroup_name, &info.full_path[prefix_len], - FILENAME_MAX); - cgroup_name[FILENAME_MAX-1] = '\0'; - - - /* start to grab data about the new group */ - group = cgroup_new_cgroup(cgroup_name); - if (group == NULL) { - printf("cannot create group '%s'\n", - cgroup_name); - ret = ECGFAIL; - goto err; - } - - ret = cgroup_get_cgroup(group); - if (ret != 0) { - printf("cannot read group '%s': %s\n", - cgroup_name, cgroup_strerror(ret)); - goto err; - } - - display_cgroup_data(group, controller, info.full_path, - prefix_len, first, program_name); - first = 0; - cgroup_free(&group); - } - } - -err: - cgroup_walk_tree_end(&handle); - if (ret == ECGEOF) - ret = 0; - - return ret; - -} - -static int is_ctlr_on_list(char controllers[CG_CONTROLLER_MAX][FILENAME_MAX], - cont_name_t wanted_conts[FILENAME_MAX]) -{ - int i = 0; - int j = 0; - - while (controllers[i][0] != '\0') { - while (wanted_conts[j][0] != '\0') { - if (strcmp(controllers[i], wanted_conts[j]) == 0) - return 1; - j++; - } - j = 0; - i++; - } - - return 0; -} - - -/* print data about input cont_name controller */ -static int parse_controllers(cont_name_t cont_names[CG_CONTROLLER_MAX], - const char *program_name) -{ - int ret = 0; - void *handle; - char path[FILENAME_MAX]; - struct cgroup_mount_point controller; - - char controllers[CG_CONTROLLER_MAX][FILENAME_MAX]; - int max = 0; - - path[0] = '\0'; - - ret = cgroup_get_controller_begin(&handle, &controller); - - /* go through the list of controllers/mount point pairs */ - while (ret == 0) { - if (strcmp(path, controller.path) == 0) { - /* if it is still the same mount point */ - if (max < CG_CONTROLLER_MAX) { - strncpy(controllers[max], - controller.name, FILENAME_MAX); - (controllers[max])[FILENAME_MAX-1] = '\0'; - max++; - } - } else { - - /* we got new mount point, print it if needed */ - if ((!(flags & FL_LIST) || - (is_ctlr_on_list(controllers, cont_names))) - && (max != 0)) { - (controllers[max])[0] = '\0'; - ret = display_controller_data( - controllers, program_name); - } - - strncpy(controllers[0], controller.name, FILENAME_MAX); - (controllers[0])[FILENAME_MAX-1] = '\0'; - - strncpy(path, controller.path, FILENAME_MAX); - path[FILENAME_MAX-1] = '\0'; - max = 1; - } - - /* the actual controller should not be printed */ - ret = cgroup_get_controller_next(&handle, &controller); - } - - if ((!(flags & FL_LIST) || - (is_ctlr_on_list(controllers, cont_names))) - && (max != 0)) { - (controllers[max])[0] = '\0'; - ret = display_controller_data( - controllers, program_name); - } - - cgroup_get_controller_end(&handle); - if (ret != ECGEOF) - return ret; - return 0; -} - -static int show_mountpoints(const char *controller) -{ - char path[FILENAME_MAX]; - int ret; - void *handle; - int quote = 0; - - if (strncmp(controller, "name=", 5) == 0) - quote = 1; - - ret = cgroup_get_subsys_mount_point_begin(controller, &handle, path); - if (ret) - return ret; - - while (ret == 0) { - if (quote) - fprintf(of, "\t\"%s\" = %s;\n", controller, path); - else - fprintf(of, "\t%s = %s;\n", controller, path); - ret = cgroup_get_subsys_mount_point_next(&handle, path); - } - cgroup_get_subsys_mount_point_end(&handle); - - if (ret != ECGEOF) - return ret; - return 0; -} - -/* parse whether data about given controller "name" should be displayed. - * If yes then the data are printed. "cont_names" is list of controllers - * which should be shown. - */ -static void parse_mountpoint(cont_name_t cont_names[CG_CONTROLLER_MAX], - char *name) -{ - int i; - - /* if there is no controller list show all mounted controllers */ - if (!(flags & FL_LIST)) { - if (show_mountpoints(name)) { - /* the controller is not mounted */ - if ((flags & FL_SILENT) == 0) - fprintf(stderr, "ERROR: %s hierarchy "\ - "not mounted\n", name); - } - return; - } - - /* there is controller list - show wanted mounted controllers only */ - for (i = 0; i <= CG_CONTROLLER_MAX-1; i++) { - if (!strncmp(cont_names[i], name, strlen(name)+1)) { - /* controller is on the list */ - if (show_mountpoints(name)) { - /* the controller is not mounted */ - if ((flags & FL_SILENT) == 0) { - fprintf(stderr, "ERROR: %s hierarchy "\ - "not mounted\n", name); - } - break; - } - break; - } - } - - return; -} - -/* print data about input mount points */ -static int parse_mountpoints(cont_name_t cont_names[CG_CONTROLLER_MAX], - const char *program_name) -{ - int ret, final_ret = 0; - void *handle; - struct controller_data info; - struct cgroup_mount_point mount; - - /* start mount section */ - fprintf(of, "mount {\n"); - - /* go through the controller list */ - ret = cgroup_get_all_controller_begin(&handle, &info); - while (ret == 0) { - - /* the controller attached to some hierarchy */ - if (info.hierarchy != 0) - parse_mountpoint(cont_names, info.name); - - /* next controller */ - ret = cgroup_get_all_controller_next(&handle, &info); - } - if (ret != ECGEOF) { - if ((flags & FL_SILENT) != 0) { - fprintf(stderr, - "E: in get next controller %s\n", - cgroup_strerror(ret)); - } - final_ret = ret; - } - cgroup_get_all_controller_end(&handle); - - /* process also named hierarchies */ - ret = cgroup_get_controller_begin(&handle, &mount); - while (ret == 0) { - if (strncmp(mount.name, "name=", 5) == 0) - parse_mountpoint(cont_names, mount.name); - ret = cgroup_get_controller_next(&handle, &mount); - } - - if (ret != ECGEOF) { - if ((flags & FL_SILENT) != 0) { - fprintf(stderr, - "E: in get next controller %s\n", - cgroup_strerror(ret)); - } - final_ret = ret; - } - cgroup_get_controller_end(&handle); - - /* finish mount section */ - fprintf(of, "}\n\n"); - return final_ret; -} - -int main(int argc, char *argv[]) -{ - int ret = 0, err; - int c; - - int i; - int c_number = 0; - cont_name_t wanted_cont[CG_CONTROLLER_MAX]; - - char bl_file[FILENAME_MAX]; /* blacklist file name */ - char wl_file[FILENAME_MAX]; /* whitelist file name */ - - static struct option long_opts[] = { - {"help", no_argument, NULL, 'h'}, - {"silent" , no_argument, NULL, 's'}, - {"blacklist", required_argument, NULL, 'b'}, - {"whitelist", required_argument, NULL, 'w'}, - {"strict", no_argument, NULL, 't'}, - {"file", required_argument, NULL, 'f'}, - {0, 0, 0, 0} - }; - - for (i = 0; i < CG_CONTROLLER_MAX; i++) - wanted_cont[i][0] = '\0'; - flags = 0; - - /* parse arguments */ - while ((c = getopt_long(argc, argv, "hsb:w:tf:", long_opts, NULL)) - > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - return 0; - case 's': - flags |= FL_SILENT; - break; - case 'b': - flags |= FL_BLACK; - strncpy(bl_file, optarg, FILENAME_MAX); - bl_file[FILENAME_MAX-1] = '\0'; - break; - case 'w': - flags |= FL_WHITE; - strncpy(wl_file, optarg, FILENAME_MAX); - wl_file[FILENAME_MAX-1] = '\0'; - break; - case 't': - flags |= FL_STRICT; - break; - case 'f': - flags |= FL_OUTPUT; - of = fopen(optarg, "w"); - if (of == NULL) { - fprintf(stderr, "%s: Failed to open file %s\n", - argv[0], optarg); - return ECGOTHER; - } - break; - default: - usage(1, argv[0]); - return -1; - } - } - - /* read the list of controllers */ - while (optind < argc) { - flags |= FL_LIST; - strncpy(wanted_cont[c_number], argv[optind], FILENAME_MAX); - (wanted_cont[c_number])[FILENAME_MAX-1] = '\0'; - c_number++; - optind++; - if (optind == CG_CONTROLLER_MAX-1) { - fprintf(stderr, "too many parameters\n"); - break; - } - } - - if ((flags & FL_OUTPUT) == 0) - of = stdout; - - /* blacklkist */ - if (flags & FL_BLACK) { - ret = load_list(bl_file, &black_list); - } else { - /* load the blacklist from the default location */ - ret = load_list(BLACKLIST_CONF, &black_list); - } - if (ret != 0) - goto finish; - - /* whitelist */ - if (flags & FL_WHITE) - ret = load_list(wl_file, &white_list); - if (ret != 0) - goto finish; - - /* print the header */ - fprintf(of, "# Configuration file generated by cgsnapshot\n"); - - /* initialize libcgroup */ - ret = cgroup_init(); - if (ret) - /* empty configuration file */ - goto finish; - - /* print mount points section */ - ret = parse_mountpoints(wanted_cont, argv[0]); - /* continue with processing on error*/ - - /* print hierarchies section */ - /*replace error from parse_mountpoints() only with another error*/ - err = parse_controllers(wanted_cont, argv[0]); - if (err) - ret = err; - -finish: - free_list(black_list); - free_list(white_list); - - if (of != stdout) - fclose(of); - - return ret; -} diff --git a/src/tools/lscgroup.c b/src/tools/lscgroup.c deleted file mode 100644 index bfb1724f..00000000 --- a/src/tools/lscgroup.c +++ /dev/null @@ -1,325 +0,0 @@ -/* Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. - * Written by Ivana Hutarova Varekova - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include "tools-common.h" - -enum flag{ - /* - * the flag set if there is a cgroup on output - * if there is no one we want to display all cgroups - */ - FL_LIST = 1 -}; - -static inline void trim_filepath(char *path) -{ - int len; - len = strlen(path) - 1; - while (path[len] == '/') - len--; - - path[len + 1] = '\0'; -} - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-h] [[-g] :] [...]\n", - program_name); - printf("List all cgroups\n"); - printf(" -g : Control group to be displayed "\ - "(-g is optional)\n"); - printf(" -h, --help Display this help\n"); -} - -/* - * if the info about controller "name" should be printed, - * then the function returns nonzero value - */ -static int is_ctlr_on_list(struct cgroup_group_spec *cgroup_list, - const char *name) -{ - int j; - - for (j = 0; cgroup_list->controllers[j] != NULL; j++) - if (strcmp(cgroup_list->controllers[j], name) == 0) - return 1; - - return 0; -} - -static void print_info(struct cgroup_file_info *info, char *name, int pref) -{ - if (info->type == CGROUP_FILE_TYPE_DIR) { - if (info->full_path[pref] == '/') - printf("%s:%s\n", name, &info->full_path[pref]); - else - printf("%s:/%s\n", name, &info->full_path[pref]); - } -} - -/* display controller:/input_path cgroups */ -static int display_controller_data(char *input_path, char *controller, char *name) -{ - int ret; - void *handle; - struct cgroup_file_info info; - char cgroup_dir_path[FILENAME_MAX]; - char input_dir_path[FILENAME_MAX]; - int lvl; - int len; - - ret = cgroup_walk_tree_begin(controller, input_path, 0, - &handle, &info, &lvl); - if (ret != 0) - return ret; - - strncpy(cgroup_dir_path, info.full_path, FILENAME_MAX); - /* remove problematic '/' characters from cgroup directory path*/ - trim_filepath(cgroup_dir_path); - - strncpy(input_dir_path, input_path, FILENAME_MAX); - - /* remove problematic '/' characters from input directory path*/ - trim_filepath(input_dir_path); - len = strlen(cgroup_dir_path) - strlen(input_dir_path); - print_info(&info, name, len); - while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) == 0) - print_info(&info, name, len); - - cgroup_walk_tree_end(&handle); - if (ret == ECGEOF) - ret = 0; - - return ret; -} - -/* - * print data about input cgroup_list cgroups - * if FL_LIST flag is set then if the function does not find - * the cgroup it returns ECGEOF - */ - -static int print_cgroup(struct cgroup_group_spec *cgroup_spec, int flags) -{ - int ret = 0; - void *handle; - struct cgroup_mount_point controller; - char path[FILENAME_MAX]; - char con_name[FILENAME_MAX]; - char all_conts[FILENAME_MAX]; - int output = 0; - - path[0] = '\0'; - con_name[0] = '\0'; - all_conts[0] = '\0'; - - ret = cgroup_get_controller_begin(&handle, &controller); - - /* go through the list of controllers/mount point pairs */ - while (ret == 0) { - if (strcmp(path, controller.path) == 0) { - /* if it is still the same mount point */ - strncat(all_conts, ",", - FILENAME_MAX-strlen(all_conts)-1); - strncat(all_conts, controller.name, - FILENAME_MAX-strlen(all_conts)-1); - } else { - /* we got new mount point, print it if needed */ - if (output) { - ret = display_controller_data( - cgroup_spec->path, - con_name, all_conts); - if (ret) - return ret; - if ((flags & FL_LIST) != 0) { - /* we succesfully finish printing */ - output = 0; - break; - } - } - - output = 0; - strncpy(all_conts, controller.name, FILENAME_MAX); - all_conts[FILENAME_MAX-1] = '\0'; - strncpy(con_name, controller.name, FILENAME_MAX); - con_name[FILENAME_MAX-1] = '\0'; - strncpy(path, controller.path, FILENAME_MAX); - path[FILENAME_MAX-1] = '\0'; - } - - /* set output flag */ - if ((output == 0) && (!(flags & FL_LIST) || - (is_ctlr_on_list(cgroup_spec, controller.name)))) - output = 1; - - /* the actual controller should not be printed */ - ret = cgroup_get_controller_next(&handle, &controller); - } - - cgroup_get_controller_end(&handle); - if (ret != ECGEOF) - return ret; - - if (output) { - ret = display_controller_data( - cgroup_spec->path, - con_name, all_conts); - } - - return ret; -} - - -static int cgroup_list_cgroups(char *tname, - struct cgroup_group_spec *cgroup_list[], - int flags) -{ - int ret = 0; - int final_ret = 0; - int i = 0; - - /* initialize libcgroup */ - ret = cgroup_init(); - if (ret) { - fprintf(stderr, "cgroups can't be listed: %s\n", - cgroup_strerror(ret)); - return ret; - } - - if ((flags & FL_LIST) == 0) { - struct cgroup_group_spec *cgroup_spec; - cgroup_spec = calloc(1, sizeof(struct cgroup_group_spec)); - /* we have to print all cgroups */ - ret = print_cgroup(cgroup_spec, flags); - free(cgroup_spec); - if (ret == 0) { - final_ret = 0; - } else { - final_ret = ret; - fprintf(stderr, "cgroups can't be listed: %s\n", - cgroup_strerror(ret)); - } - } else { - /* we have he list of controllers which should be print */ - while ((cgroup_list[i] != NULL) - && ((ret == ECGEOF) || (ret == 0))) { - ret = print_cgroup(cgroup_list[i], flags); - if (ret != 0) { - if (ret == ECGEOF) { - /* controller was not found */ - final_ret = ECGFAIL; - } else { - /* other problem */ - final_ret = ret; - } - fprintf(stderr, - "%s: cannot find group %s..:%s: %s\n", - tname, cgroup_list[i]->controllers[0], - cgroup_list[i]->path, - cgroup_strerror(final_ret)); - } - i++; - } - } - return final_ret; -} - -int main(int argc, char *argv[]) -{ - - int ret = 0; - int c; - int i; - - int flags = 0; - - struct cgroup_group_spec *cgroup_list[CG_HIER_MAX]; - - static struct option options[] = { - {"help", 0, 0, 'h'}, - {"group", required_argument, NULL, 'g'}, - {0, 0, 0, 0} - }; - - memset(cgroup_list, 0, sizeof(cgroup_list)); - - /* parse arguments */ - while ((c = getopt_long(argc, argv, "hg:", options, NULL)) > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - ret = 0; - goto err; - case 'g': - ret = parse_cgroup_spec(cgroup_list, optarg, - CG_HIER_MAX); - if (ret) { - fprintf(stderr, "%s: cgroup controller" - " and path parsing failed (%s)\n", - argv[0], optarg); - return ret; - } - break; - default: - usage(1, argv[0]); - ret = 1; - goto err; - } - } - - /* read the list of controllers */ - while (optind < argc) { - ret = parse_cgroup_spec(cgroup_list, argv[optind], - CG_HIER_MAX); - if (ret) { - fprintf(stderr, "%s: cgroup controller" - " and path parsing failed (%s)\n", - argv[0], argv[optind]); - return -1; - } - optind++; - } - - if (cgroup_list[0] != NULL) { - /* cgroups on input */ - flags |= FL_LIST; - } - - /* print the information - based on list of input cgroups and flags */ - ret = cgroup_list_cgroups(argv[0], cgroup_list, flags); - -err: - if (cgroup_list[0]) { - for (i = 0; i < CG_HIER_MAX; i++) { - if (cgroup_list[i]) - cgroup_free_group_spec(cgroup_list[i]); - } - } - - - return ret; -} diff --git a/src/tools/lssubsys.c b/src/tools/lssubsys.c deleted file mode 100644 index bd2e5d5f..00000000 --- a/src/tools/lssubsys.c +++ /dev/null @@ -1,286 +0,0 @@ -/* " Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. - * " Written by Ivana Hutarova Varekova - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include -#include -#include -#include -#include - -#include -#include - -enum flag{ - FL_MOUNT = 1, /* show the mount points */ - FL_LIST = 2, - FL_ALL = 4, /* show all subsystems - not mounted too */ - FL_HIERARCHY = 8, /* show info about hierarchies */ - FL_MOUNT_ALL = 16 /* show all mount points of hierarchies */ -}; - -typedef char cont_name_t[FILENAME_MAX]; - -static void usage(int status, const char *program_name) -{ - if (status != 0) { - fprintf(stderr, "Wrong input parameters," - " try %s -h' for more information.\n", - program_name); - return; - } - printf("Usage: %s [-i] [-m] [-M] [controller] [...]\n"\ - " or: %s [-a] [-i] [-m] [-M]\n", program_name, program_name); - printf("List information about given controller(s) If no controller "\ - "is set list information about all mounted controllers.\n"); - printf(" -a, --all Display information "\ - "about all controllers (including not mounted ones)\n"); - printf(" -h, --help Display this help\n"); - printf(" -i, --hierarchies Display information about "\ - "hierarchies\n"); - printf(" -m, --mount-points Display mount points\n"); - printf(" -M, --all-mount-points Display all mount points\n"); -} - -static int print_controller_mount(const char *controller, - int flags, cont_name_t cont_names, int hierarchy) -{ - int ret = 0; - void *handle; - char path[FILENAME_MAX]; - - if (!(flags & FL_MOUNT) && !(flags & FL_HIERARCHY)) { - /* print only hierarchy name */ - printf("%s\n", cont_names); - } - if (!(flags & FL_MOUNT) && (flags & FL_HIERARCHY)) { - /* print only hierarchy name and number*/ - printf("%s %d\n", cont_names, hierarchy); - } - if (flags & FL_MOUNT) { - /* print hierarchy name and mount point(s) */ - ret = cgroup_get_subsys_mount_point_begin(controller, &handle, - path); - /* intentionally ignore error from above call */ - while (ret == 0) { - printf("%s %s\n", cont_names, path); - if (!(flags & FL_MOUNT_ALL)) - /* first mount record is enough */ - goto stop; - ret = cgroup_get_subsys_mount_point_next(&handle, path); - } - if (ret == ECGEOF) - ret = 0; -stop: - cgroup_get_subsys_mount_point_end(&handle); - } - return ret; -} - -/* display all controllers attached to the given hierarchy */ -static int print_all_controllers_in_hierarchy(const char *tname, - int hierarchy, int flags) -{ - int ret = 0; - void *handle; - struct controller_data info; - int first = 1; - cont_name_t cont_names; - cont_name_t cont_name; - - /* - * Initialize libcgroup and intentionally ignore its result, - * no mounted controller is valid use case. - */ - (void) cgroup_init(); - - ret = cgroup_get_all_controller_begin(&handle, &info); - if ((ret != 0) && (ret != ECGEOF)) { - fprintf(stderr, "cannot read controller data: %s\n", - cgroup_strerror(ret)); - return ret; - } - - while (ret != ECGEOF) { - /* controller is in the hierrachy */ - if (info.hierarchy != hierarchy) - goto next; - - if (first) { - /* the first controller in the hierarchy */ - memset(cont_name, 0, FILENAME_MAX); - strncpy(cont_name, info.name, FILENAME_MAX-1); - memset(cont_names, 0, FILENAME_MAX); - strncpy(cont_names, info.name, FILENAME_MAX-1); - first = 0; - } else { - /* the next controller in the hierarchy */ - strncat(cont_names, ",", FILENAME_MAX-1); - strncat(cont_names, info.name, FILENAME_MAX-1); - } -next: - ret = cgroup_get_all_controller_next(&handle, &info); - if (ret && ret != ECGEOF) - goto end; - } - - ret = print_controller_mount(cont_name, - flags, cont_names, hierarchy); - -end: - cgroup_get_all_controller_end(&handle); - - if (ret == ECGEOF) - ret = 0; - - return ret; -} - - -/* go through the list of all controllers gather them based on hierarchy number - and print them */ -static int cgroup_list_all_controllers(const char *tname, - cont_name_t cont_name[CG_CONTROLLER_MAX], int c_number, int flags) -{ - int ret = 0; - void *handle; - struct controller_data info; - - int h_list[CG_CONTROLLER_MAX]; /* list of hierarchies */ - int counter = 0; - int j; - int is_on_list = 0; - - ret = cgroup_get_all_controller_begin(&handle, &info); - while (ret == 0) { - if (info.hierarchy == 0) { - /* the controller is not attached to any hierrachy */ - if (flags & FL_ALL) - /* display only if -a flag is set */ - printf("%s\n", info.name); - } - is_on_list = 0; - j = 0; - while ((is_on_list == 0) && (j < c_number)) { - if (strcmp(info.name, cont_name[j]) == 0) { - is_on_list = 1; - break; - } - j++; - } - - if ((info.hierarchy != 0) && - ((flags & FL_ALL) || - (!(flags & FL_LIST) || (is_on_list == 1)))) { - /* the controller is attached to some hierarchy - and either should be output all controllers, - or the controller is on the output list */ - - h_list[counter] = info.hierarchy; - counter++; - for (j = 0; j < counter-1; j++) { - /* - * the hierarchy already was on the list - * so remove the new record - */ - if (h_list[j] == info.hierarchy) { - counter--; - break; - } - } - } - - ret = cgroup_get_all_controller_next(&handle, &info); - } - cgroup_get_all_controller_end(&handle); - if (ret == ECGEOF) - ret = 0; - if (ret) { - fprintf(stderr, - "cgroup_get_controller_begin/next failed (%s)\n", - cgroup_strerror(ret)); - return ret; - } - - - for (j = 0; j < counter; j++) - ret = print_all_controllers_in_hierarchy(tname, - h_list[j], flags); - - return ret; - -} - -int main(int argc, char *argv[]) -{ - - int ret = 0; - int c; - - int flags = 0; - - int i; - int c_number = 0; - cont_name_t cont_name[CG_CONTROLLER_MAX]; - - static struct option options[] = { - {"help", 0, 0, 'h'}, - {"mount-points", 0, 0, 'm'}, - {"all-mount-points", 0, 0, 'M'}, - {"all", 0, 0, 'a'}, - {"hierarchies", 0, 0, 'i'}, - {0, 0, 0, 0} - }; - - for (i = 0; i < CG_CONTROLLER_MAX; i++) - cont_name[i][0] = '\0'; - - /* parse arguments */ - while ((c = getopt_long(argc, argv, "mMhai", options, NULL)) > 0) { - switch (c) { - case 'h': - usage(0, argv[0]); - return 0; - case 'm': - flags |= FL_MOUNT; - break; - case 'M': - flags |= FL_MOUNT | FL_MOUNT_ALL; - break; - case 'a': - flags |= FL_ALL; - break; - case 'i': - flags |= FL_HIERARCHY; - break; - default: - usage(1, argv[0]); - return -1; - } - } - - /* read the list of controllers */ - while (optind < argc) { - flags |= FL_LIST; - strncpy(cont_name[c_number], argv[optind], FILENAME_MAX); - cont_name[c_number][FILENAME_MAX-1] = '\0'; - c_number++; - optind++; - if (optind == CG_CONTROLLER_MAX) { - fprintf(stderr, "Warning: too many parameters\n"); - break; - } - } - - ret = cgroup_list_all_controllers(argv[0], cont_name, c_number, flags); - - return ret; -} diff --git a/src/tools/tools-common.c b/src/tools/tools-common.c deleted file mode 100644 index 211a49a9..00000000 --- a/src/tools/tools-common.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright Red Hat, Inc. 2009 - * - * Author: Vivek Goyal - * Jan Safranek - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -/* for asprintf */ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "tools-common.h" - -int parse_cgroup_spec(struct cgroup_group_spec **cdptr, char *optarg, - int capacity) -{ - struct cgroup_group_spec *ptr; - int i, j; - char *cptr, *pathptr, *temp; - - ptr = *cdptr; - - /* Find first free entry inside the cgroup data array */ - for (i = 0; i < capacity; i++, ptr++) { - if (!cdptr[i]) - break; - } - - if (i == capacity) { - /* No free slot found */ - fprintf(stderr, "Max allowed hierarchies %d reached\n", - capacity); - return -1; - } - - /* Extract list of controllers */ - cptr = strtok(optarg, ":"); - cgroup_dbg("list of controllers is %s\n", cptr); - if (!cptr) - return -1; - - /* Extract cgroup path */ - pathptr = strtok(NULL, ":"); - cgroup_dbg("cgroup path is %s\n", pathptr); - if (!pathptr) - return -1; - - /* instanciate cgroup_data. */ - cdptr[i] = calloc(1, sizeof(struct cgroup_group_spec)); - if (!cdptr[i]) { - fprintf(stderr, "%s\n", strerror(errno)); - return -1; - } - /* Convert list of controllers into an array of strings. */ - j = 0; - do { - if (j == 0) - temp = strtok(cptr, ","); - else - temp = strtok(NULL, ","); - - if (temp) { - cdptr[i]->controllers[j] = strdup(temp); - if (!cdptr[i]->controllers[j]) { - free(cdptr[i]); - fprintf(stderr, "%s\n", strerror(errno)); - return -1; - } - } - j++; - } while (temp && jpath, pathptr, FILENAME_MAX); - cdptr[i]->path[FILENAME_MAX-1] = '\0'; - - return 0; -} - - -/** - * Free a single cgroup_group_spec structure - * <--->@param cl The structure to free from memory. - */ -void cgroup_free_group_spec(struct cgroup_group_spec *cl) -{ - /* Loop variable */ - int i = 0; - - /* Make sure our structure is not NULL, first. */ - if (!cl) { - cgroup_dbg("Warning: Attempted to free NULL rule.\n"); - return; - } - - /* We must free any used controller strings, too. */ - for (i = 0; i < CG_CONTROLLER_MAX; i++) { - if (cl->controllers[i]) - free(cl->controllers[i]); - } - - free(cl); -} - - -int cgroup_string_list_init(struct cgroup_string_list *list, - int initial_size) -{ - if (list == NULL) - return ECGINVAL; - list->items = calloc(initial_size, sizeof(char *)); - if (!list->items) - return ECGFAIL; - list->count = 0; - list->size = initial_size; - return 0; -} - -void cgroup_string_list_free(struct cgroup_string_list *list) -{ - int i; - - if (list == NULL) - return; - - if (list->items == NULL) - return; - - for (i = 0; i < list->count; i++) - free(list->items[i]); - - free(list->items); -} - -int cgroup_string_list_add_item(struct cgroup_string_list *list, - const char *item) -{ - if (list == NULL) - return ECGINVAL; - if (list->size <= list->count) { - char **tmp = realloc(list->items, - sizeof(char *) * list->size*2); - if (tmp == NULL) - return ECGFAIL; - list->items = tmp; - list->size = list->size * 2; - } - - list->items[list->count] = strdup(item); - if (list->items[list->count] == NULL) - return ECGFAIL; - list->count++; - return 0; -} - -static int _compare_string(const void *a, const void *b) -{ - const char *sa = * (char * const *) a; - const char *sb = * (char * const *) b; - return strcmp(sa, sb); -} - - -int cgroup_string_list_add_directory(struct cgroup_string_list *list, - char *dirname, char *program_name) -{ - int start, ret, count = 0; - DIR *d; - struct dirent *item; - - if (list == NULL) - return ECGINVAL; - - start = list->count; - - d = opendir(dirname); - if (!d) { - fprintf(stderr, "%s: cannot open %s: %s\n", program_name, - dirname, strerror(errno)); - exit(1); - } - - do { - errno = 0; - item = readdir(d); - if (item && (item->d_type == DT_REG - || item->d_type == DT_LNK)) { - char *tmp; - ret = asprintf(&tmp, "%s/%s", dirname, item->d_name); - if (ret < 0) { - fprintf(stderr, "%s: out of memory\n", - program_name); - exit(1); - } - ret = cgroup_string_list_add_item(list, tmp); - free(tmp); - count++; - if (ret) { - fprintf(stderr, "%s: %s\n", - program_name, - cgroup_strerror(ret)); - exit(1); - } - } - if (!item && errno) { - fprintf(stderr, "%s: cannot read %s: %s\n", - program_name, dirname, strerror(errno)); - exit(1); - } - } while (item != NULL); - closedir(d); - - /* sort the names found in the directory */ - if (count > 0) - qsort(&list->items[start], count, sizeof(char *), - _compare_string); - return 0; -} - - -/* allowed mode strings are octal version: "755" */ -int parse_mode(char *string, mode_t *pmode, const char *program_name) -{ - char *end; - long mode; - size_t len; - - len = strlen(string); - if (len < 3 || len > 4) - goto err; - - errno = 0; - mode = strtol(string, &end, 8); - if (errno != 0 || *end != '\0') - goto err; - *pmode = mode; - return 0; - -err: - *pmode = 0; - fprintf(stdout, "%s wrong mode format %s\n", program_name, string); - return -1; -} - -int parse_uid_gid(char *string, uid_t *uid, gid_t *gid, - const char *program_name) -{ - char *grp_string = NULL; - char *pwd_string = NULL; - struct passwd *pwd; - struct group *grp; - - *uid = *gid = NO_UID_GID; - - if (string[0] == ':') - grp_string = strtok(string, ":"); - else { - pwd_string = strtok(string, ":"); - if (pwd_string != NULL) - grp_string = strtok(NULL, ":"); - } - - if (pwd_string != NULL) { - pwd = getpwnam(pwd_string); - if (pwd != NULL) { - *uid = pwd->pw_uid; - } else { - fprintf(stderr, "%s: can't find uid of user %s.\n", - program_name, pwd_string); - return -1; - } - } - if (grp_string != NULL) { - grp = getgrnam(grp_string); - if (grp != NULL) - *gid = grp->gr_gid; - else { - fprintf(stderr, "%s: can't find gid of group %s.\n", - program_name, grp_string); - return -1; - } - } - return 0; -} diff --git a/src/tools/tools-common.h b/src/tools/tools-common.h deleted file mode 100644 index c723eb4c..00000000 --- a/src/tools/tools-common.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Red Hat, Inc. 2009 - * - * Author: Vivek Goyal - * Jan Safranek - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __TOOLS_COMMON - -#define __TOOLS_COMMON - -#include "config.h" -#include -#include "../libcgroup-internal.h" - -#define cgroup_err(x...) cgroup_log(CGROUP_LOG_ERROR, x) -#define cgroup_warn(x...) cgroup_log(CGROUP_LOG_WARNING, x) -#define cgroup_info(x...) cgroup_log(CGROUP_LOG_INFO, x) -#define cgroup_dbg(x...) cgroup_log(CGROUP_LOG_DEBUG, x) - -/** - * Auxiliary specifier of group, used to store parsed command line options. - */ -struct cgroup_group_spec { - char path[FILENAME_MAX]; - char *controllers[CG_CONTROLLER_MAX]; -}; - - -/** - * Simple dynamic array of strings. - */ -struct cgroup_string_list { - char **items; - int size; - int count; -}; - -/** - * Parse command line option with group specifier into provided data structure. - * The option must have form of 'controller1,controller2,..:group_name'. - * - * The parsed list of controllers and group name is added at the end of - * provided cdptr, i.e. on place of first NULL cgroup_group_spec*. - * - * @param cdptr Target data structure to fill. New item is allocated and added - * at the end. - * @param optarg Argument to parse. - * @param capacity Capacity of the cdptr array. - * @return 0 on success, != 0 on error. - */ -int parse_cgroup_spec(struct cgroup_group_spec **cdptr, char *optarg, - int capacity); - -/** - * Free a single cgroup_group_spec structure. - * @param cl The structure to free from memory - */ -void cgroup_free_group_spec(struct cgroup_group_spec *cl); - - -/** - * Initialize a new list. - * @param list List to initialize. - * @param initial_size Initial size of the list to pre-allocate. - */ -int cgroup_string_list_init(struct cgroup_string_list *list, - int initial_size); - -/** - * Destroy a list, automatically freeing all its items. - * @param list List to destroy. - */ -void cgroup_string_list_free(struct cgroup_string_list *list); - -/** - * Adds new item to the list. It automatically resizes underlying array if - * needed. - * @param list List to modify. - * @param item Item to add. The item is automatically copied to new buffer. - */ -int cgroup_string_list_add_item(struct cgroup_string_list *list, - const char *item); - -/** - * Add alphabetically sorted files present in given directory (without subdirs) - * to list of strings. The function exits on error. - * @param list The list to add files to. - * @param dirname Full path to directory to examime. - * @param program_name Name of the executable, it will be used for printing - * errors to stderr. - * - */ -int cgroup_string_list_add_directory(struct cgroup_string_list *list, - char *dirname, char *program_name); - - -/** - * Parse file permissions as octal number. - * @param string A string to parse, must contain 3-4 characters '0'-'7'. - * @param pmode Parsed mode. - * @oaram program_name Argv[0] to show error messages. - */ -int parse_mode(char *string, mode_t *pmode, const char *program_name); - -/** - * Parse UID and GID from string in form "user:group". - * @param string A string to parse. - * @param uid Parsed UID (-1 if 'user' is missing in the string). - * @param gid Parsed GID (-1 if 'group' is missing in the string). - * @param program_name Argv[0] to show error messages. - */ -int parse_uid_gid(char *string, uid_t *uid, gid_t *gid, - const char *program_name); - -#endif /* TOOLS_COMMON */ diff --git a/src/wrapper.c b/src/wrapper.c deleted file mode 100644 index b7932545..00000000 --- a/src/wrapper.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright IBM Corporation. 2008 - * - * Author: Dhaval Giani - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Code initiated and designed by Dhaval Giani. All faults are most likely - * his mistake. - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -static void init_cgroup(struct cgroup *cgroup) -{ - cgroup->task_fperm = cgroup->control_fperm = cgroup->control_dperm = NO_PERMS; - cgroup->control_gid = cgroup->control_uid = cgroup->tasks_gid = - cgroup->tasks_uid = NO_UID_GID; -} - -void init_cgroup_table(struct cgroup *cgroups, size_t count) -{ - size_t i; - - for (i = 0; i < count; ++i) - init_cgroup(&cgroups[i]); -} - -struct cgroup *cgroup_new_cgroup(const char *name) -{ - struct cgroup *cgroup = calloc(1, sizeof(struct cgroup)); - if (!cgroup) - return NULL; - - init_cgroup(cgroup); - strncpy(cgroup->name, name, sizeof(cgroup->name) - 1); - - return cgroup; -} - -struct cgroup_controller *cgroup_add_controller(struct cgroup *cgroup, - const char *name) -{ - int i; - struct cgroup_controller *controller; - - if (!cgroup) - return NULL; - - /* - * Still not sure how to handle the failure here. - */ - if (cgroup->index >= CG_CONTROLLER_MAX) - return NULL; - - /* - * Still not sure how to handle the failure here. - */ - for (i = 0; i < cgroup->index; i++) { - if (strncmp(name, cgroup->controller[i]->name, - sizeof(cgroup->controller[i]->name)) == 0) - return NULL; - } - - controller = calloc(1, sizeof(struct cgroup_controller)); - - if (!controller) - return NULL; - - strncpy(controller->name, name, sizeof(controller->name) - 1); - controller->cgroup = cgroup; - controller->index = 0; - - cgroup->controller[cgroup->index] = controller; - cgroup->index++; - - return controller; -} - -int cgroup_add_all_controllers(struct cgroup *cgroup) -{ - int ret; - void *handle; - struct controller_data info; - struct cgroup_controller *cgc; - - /* go through the controller list */ - ret = cgroup_get_all_controller_begin(&handle, &info); - if ((ret != 0) && (ret != ECGEOF)) { - fprintf(stderr, "cannot read controller data: %s\n", - cgroup_strerror(ret)); - return ret; - } - - while (ret == 0) { - if (info.hierarchy == 0) { - /* the controller is not attached to any hierarchy - skip it */ - goto next; - } - - /* add mounted controller to cgroup structure */ - cgc = cgroup_add_controller(cgroup, info.name); - if (!cgc) { - ret = ECGINVAL; - fprintf(stderr, "controller %s can't be add\n", - info.name); - } - -next: - ret = cgroup_get_all_controller_next(&handle, &info); - if (ret && ret != ECGEOF) - goto end; - } - -end: - cgroup_get_all_controller_end(&handle); - - if (ret == ECGEOF) - ret = 0; - - if (ret) - fprintf(stderr, - "cgroup_get_controller_begin/next failed (%s)\n", - cgroup_strerror(ret)); - - return ret; -} - -void cgroup_free_controllers(struct cgroup *cgroup) -{ - int i, j; - - if (!cgroup) - return; - - for (i = 0; i < cgroup->index; i++) { - for (j = 0; j < cgroup->controller[i]->index; j++) - free(cgroup->controller[i]->values[j]); - cgroup->controller[i]->index = 0; - free(cgroup->controller[i]); - } - cgroup->index = 0; -} - -void cgroup_free(struct cgroup **cgroup) -{ - struct cgroup *cg = *cgroup; - - /* - * Passing NULL pointers is OK. We just return. - */ - if (!cg) - return; - - cgroup_free_controllers(cg); - free(cg); - *cgroup = NULL; -} - -int cgroup_add_value_string(struct cgroup_controller *controller, - const char *name, const char *value) -{ - int i; - struct control_value *cntl_value; - - if (!controller) - return ECGINVAL; - - if (controller->index >= CG_NV_MAX) - return ECGMAXVALUESEXCEEDED; - - for (i = 0; i < controller->index && i < CG_NV_MAX; i++) { - if (!strcmp(controller->values[i]->name, name)) - return ECGVALUEEXISTS; - } - - cntl_value = calloc(1, sizeof(struct control_value)); - - if (!cntl_value) - return ECGCONTROLLERCREATEFAILED; - - if (strlen(value) >= sizeof(cntl_value->value)) { - fprintf(stderr, "value exceeds the maximum of %d characters\n", - sizeof(cntl_value->value) - 1); - free(cntl_value); - return ECGCONFIGPARSEFAIL; - } - - strncpy(cntl_value->name, name, sizeof(cntl_value->name)); - cntl_value->name[sizeof(cntl_value->name)-1] = '\0'; - strncpy(cntl_value->value, value, sizeof(cntl_value->value)); - cntl_value->value[sizeof(cntl_value->value)-1] = '\0'; - cntl_value->dirty = true; - controller->values[controller->index] = cntl_value; - controller->index++; - - return 0; -} - -int cgroup_add_value_int64(struct cgroup_controller *controller, - const char *name, int64_t value) -{ - int ret; - char *val; - - ret = asprintf(&val, "%"PRId64, value); - if (ret < 0) { - last_errno = errno; - return ECGOTHER; - } - - ret = cgroup_add_value_string(controller, name, val); - free(val); - - return ret; -} - -int cgroup_add_value_uint64(struct cgroup_controller *controller, - const char *name, u_int64_t value) -{ - int ret; - char *val; - - ret = asprintf(&val, "%" PRIu64, value); - if (ret < 0) { - last_errno = errno; - return ECGOTHER; - } - - ret = cgroup_add_value_string(controller, name, val); - free(val); - - return ret; -} - -int cgroup_add_value_bool(struct cgroup_controller *controller, - const char *name, bool value) -{ - int ret; - char *val; - - if (value) - val = strdup("1"); - else - val = strdup("0"); - if (!val) { - last_errno = errno; - return ECGOTHER; - } - - ret = cgroup_add_value_string(controller, name, val); - free(val); - - return ret; -} - -int cgroup_compare_controllers(struct cgroup_controller *cgca, - struct cgroup_controller *cgcb) -{ - int i; - - if (!cgca || !cgcb) - return ECGINVAL; - - if (strcmp(cgca->name, cgcb->name)) - return ECGCONTROLLERNOTEQUAL; - - if (cgca->index != cgcb->index) - return ECGCONTROLLERNOTEQUAL; - - for (i = 0; i < cgca->index; i++) { - struct control_value *cva = cgca->values[i]; - struct control_value *cvb = cgcb->values[i]; - - if (strcmp(cva->name, cvb->name)) - return ECGCONTROLLERNOTEQUAL; - - if (strcmp(cva->value, cvb->value)) - return ECGCONTROLLERNOTEQUAL; - } - return 0; -} - -int cgroup_compare_cgroup(struct cgroup *cgroup_a, struct cgroup *cgroup_b) -{ - int i; - - if (!cgroup_a || !cgroup_b) - return ECGINVAL; - - if (strcmp(cgroup_a->name, cgroup_b->name)) - return ECGROUPNOTEQUAL; - - if (cgroup_a->tasks_uid != cgroup_b->tasks_uid) - return ECGROUPNOTEQUAL; - - if (cgroup_a->tasks_gid != cgroup_b->tasks_gid) - return ECGROUPNOTEQUAL; - - if (cgroup_a->control_uid != cgroup_b->control_uid) - return ECGROUPNOTEQUAL; - - if (cgroup_a->control_gid != cgroup_b->control_gid) - return ECGROUPNOTEQUAL; - - if (cgroup_a->index != cgroup_b->index) - return ECGROUPNOTEQUAL; - - for (i = 0; i < cgroup_a->index; i++) { - struct cgroup_controller *cgca = cgroup_a->controller[i]; - struct cgroup_controller *cgcb = cgroup_b->controller[i]; - - if (cgroup_compare_controllers(cgca, cgcb)) - return ECGCONTROLLERNOTEQUAL; - } - return 0; -} - -int cgroup_set_uid_gid(struct cgroup *cgroup, uid_t tasks_uid, gid_t tasks_gid, - uid_t control_uid, gid_t control_gid) -{ - if (!cgroup) - return ECGINVAL; - - cgroup->tasks_uid = tasks_uid; - cgroup->tasks_gid = tasks_gid; - cgroup->control_uid = control_uid; - cgroup->control_gid = control_gid; - - return 0; -} - -int cgroup_get_uid_gid(struct cgroup *cgroup, uid_t *tasks_uid, - gid_t *tasks_gid, uid_t *control_uid, gid_t *control_gid) -{ - if (!cgroup) - return ECGINVAL; - - *tasks_uid = cgroup->tasks_uid; - *tasks_gid = cgroup->tasks_gid; - *control_uid = cgroup->control_uid; - *control_gid = cgroup->control_gid; - - return 0; -} - -struct cgroup_controller *cgroup_get_controller(struct cgroup *cgroup, - const char *name) -{ - int i; - struct cgroup_controller *cgc; - - if (!cgroup) - return NULL; - - for (i = 0; i < cgroup->index; i++) { - cgc = cgroup->controller[i]; - - if (!strcmp(cgc->name, name)) - return cgc; - } - - return NULL; -} - -int cgroup_get_value_string(struct cgroup_controller *controller, - const char *name, char **value) -{ - int i; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - - if (!strcmp(val->name, name)) { - *value = strdup(val->value); - - if (!*value) - return ECGOTHER; - - return 0; - } - } - - return ECGROUPVALUENOTEXIST; - -} - -int cgroup_set_value_string(struct cgroup_controller *controller, - const char *name, const char *value) -{ - int i; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - if (!strcmp(val->name, name)) { - strncpy(val->value, value, CG_VALUE_MAX); - val->value[sizeof(val->value)-1] = '\0'; - val->dirty = true; - return 0; - } - } - - return cgroup_add_value_string(controller, name, value); -} - -int cgroup_get_value_int64(struct cgroup_controller *controller, - const char *name, int64_t *value) -{ - int i; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - - if (!strcmp(val->name, name)) { - - if (sscanf(val->value, "%" SCNd64, value) != 1) - return ECGINVAL; - - return 0; - } - } - - return ECGROUPVALUENOTEXIST; -} - -int cgroup_set_value_int64(struct cgroup_controller *controller, - const char *name, int64_t value) -{ - int i; - int ret; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - - if (!strcmp(val->name, name)) { - ret = snprintf(val->value, - sizeof(val->value), "%" PRId64, value); - - if (ret >= sizeof(val->value) || ret < 0) - return ECGINVAL; - - val->dirty = true; - return 0; - } - } - - return cgroup_add_value_int64(controller, name, value); -} - -int cgroup_get_value_uint64(struct cgroup_controller *controller, - const char *name, u_int64_t *value) -{ - int i; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - if (!strcmp(val->name, name)) { - - if (sscanf(val->value, "%" SCNu64, value) != 1) - return ECGINVAL; - - return 0; - } - } - - return ECGROUPVALUENOTEXIST; -} - -int cgroup_set_value_uint64(struct cgroup_controller *controller, - const char *name, u_int64_t value) -{ - int i; - int ret; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - - if (!strcmp(val->name, name)) { - ret = snprintf(val->value, - sizeof(val->value), "%" PRIu64, value); - - if (ret >= sizeof(val->value) || ret < 0) - return ECGINVAL; - - val->dirty = true; - return 0; - } - } - - return cgroup_add_value_uint64(controller, name, value); -} - -int cgroup_get_value_bool(struct cgroup_controller *controller, - const char *name, bool *value) -{ - int i; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - - if (!strcmp(val->name, name)) { - int cgc_val; - - if (sscanf(val->value, "%d", &cgc_val) != 1) - return ECGINVAL; - - if (cgc_val) - *value = true; - else - *value = false; - - return 0; - } - } - return ECGROUPVALUENOTEXIST; -} - -int cgroup_set_value_bool(struct cgroup_controller *controller, - const char *name, bool value) -{ - int i; - int ret; - - if (!controller) - return ECGINVAL; - - for (i = 0; i < controller->index; i++) { - struct control_value *val = controller->values[i]; - - if (!strcmp(val->name, name)) { - if (value) { - ret = snprintf(val->value, - sizeof(val->value), "1"); - } else { - ret = snprintf(val->value, - sizeof(val->value), "0"); - } - - if (ret >= sizeof(val->value) || ret < 0) - return ECGINVAL; - - val->dirty = true; - return 0; - - } - } - - return cgroup_add_value_bool(controller, name, value); -} - -struct cgroup *create_cgroup_from_name_value_pairs(const char *name, - struct control_value *name_value, int nv_number) -{ - struct cgroup *src_cgroup; - struct cgroup_controller *cgc; - char con[FILENAME_MAX]; - - int ret; - int i; - - /* create source cgroup */ - src_cgroup = cgroup_new_cgroup(name); - if (!src_cgroup) { - fprintf(stderr, "can't create cgroup: %s\n", - cgroup_strerror(ECGFAIL)); - goto scgroup_err; - } - - /* add pairs name-value to - relevant controllers of this cgroup */ - for (i = 0; i < nv_number; i++) { - - if ((strchr(name_value[i].name, '.')) == NULL) { - fprintf(stderr, "wrong -r parameter (%s=%s)\n", - name_value[i].name, name_value[i].value); - goto scgroup_err; - } - - strncpy(con, name_value[i].name, FILENAME_MAX - 1); - strtok(con, "."); - - /* find out whether we have to add the controller or - cgroup already contains it */ - cgc = cgroup_get_controller(src_cgroup, con); - if (!cgc) { - /* add relevant controller */ - cgc = cgroup_add_controller(src_cgroup, con); - if (!cgc) { - fprintf(stderr, "controller %s can't be add\n", - con); - goto scgroup_err; - } - } - - /* add name-value pair to this controller */ - ret = cgroup_add_value_string(cgc, - name_value[i].name, name_value[i].value); - if (ret) { - fprintf(stderr, "name-value pair %s=%s can't be set\n", - name_value[i].name, name_value[i].value); - goto scgroup_err; - } - } - - return src_cgroup; -scgroup_err: - cgroup_free(&src_cgroup); - return NULL; -} - -int cgroup_get_value_name_count(struct cgroup_controller *controller) -{ - if (!controller) - return -1; - - return controller->index; -} - - -char *cgroup_get_value_name(struct cgroup_controller *controller, int index) -{ - - if (!controller) - return NULL; - - if (index < controller->index) - return (controller->values[index])->name; - else - return NULL; -} - -char *cgroup_get_cgroup_name(struct cgroup *cgroup) -{ - if (!cgroup) - return NULL; - - return cgroup->name; -}