pax_global_header00006660000000000000000000000064131560060440014511gustar00rootroot0000000000000052 comment=fe1c5e41e6bdb78043dad8fa863fc2df66d1dadf systemd-bootchart-233/000077500000000000000000000000001315600604400150355ustar00rootroot00000000000000systemd-bootchart-233/.gitignore000066400000000000000000000005131315600604400170240ustar00rootroot00000000000000*.a *.cache *.html *.la *.lo *.log *.o *.plist *.pyc *.stamp *.swp *.trs *~ .config.args .deps/ .dirstamp .libs/ /*.gcda /*.gcno /*.tar.bz2 /*.tar.gz /*.tar.xz /build-aux /libtool /Makefile /TAGS /GPATH /GRTAGS /GSYMS /GTAGS /systemd-bootchart Makefile.in aclocal.m4 config.h config.h.in config.log config.status configure stamp-* systemd-bootchart-233/.travis.yml000066400000000000000000000016251315600604400171520ustar00rootroot00000000000000language: c sudo: false matrix: include: - os: linux dist: trusty compiler: gcc addons: apt: sources: [ 'ubuntu-toolchain-r-test' ] packages: [ 'intltool', 'gcc-7' ] env: - MATRIX_EVAL="CC=gcc-7 && CFLAGS='-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -ggdb3 -fvar-tracking-assignments -Og'" - os: linux dist: trusty compiler: clang addons: apt: sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0'] packages: [ 'intltool', 'clang-4.0'] env: - MATRIX_EVAL="CC=clang-4.0 && CFLAGS='-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -ggdb3 -fvar-tracking-assignments -Og'" script: - eval "${MATRIX_EVAL}" - ./autogen.sh && ./configure --without-libsystemd --disable-man && make -j2 && make -j2 -k check after_failure: - cat config.log systemd-bootchart-233/LICENSE.GPL2000066400000000000000000000431031315600604400165460ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. systemd-bootchart-233/LICENSE.LGPL2.1000066400000000000000000000636421315600604400170330ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! systemd-bootchart-233/Makefile.am000066400000000000000000000126271315600604400171010ustar00rootroot00000000000000# -*- Mode: makefile; indent-tabs-mode: t -*- # # This file is part of systemd-bootchart # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # systemd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_MAKEFLAGS = --no-print-directory AUTOMAKE_OPTIONS = color-tests parallel-tests GCC_COLORS ?= 'ooh, shiny!' export GCC_COLORS SUBDIRS = . # remove targets if the command fails .DELETE_ON_ERROR: # keep intermediate files .SECONDARY: # Keep the test-suite.log .PRECIOUS: $(TEST_SUITE_LOG) Makefile # Dirs of external packages systemdir=@systemdir@ # And these are the special ones for / rootprefix=@rootprefix@ rootbindir=$(rootprefix)/bin rootlibexecdir=$(rootprefix)/lib/systemd pkgsysconfdir=$(sysconfdir)/systemd systemunitdir=$(rootprefix)/lib/systemd/system AM_CFLAGS = $(OUR_CFLAGS) AM_LDFLAGS = $(OUR_LDFLAGS) AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ -DPKGSYSCONFDIR=\"$(pkgsysconfdir)\" \ -DSYSTEM_CONFIG_UNIT_PATH=\"$(pkgsysconfdir)/system\" \ -DSYSTEM_DATA_UNIT_PATH=\"$(systemunitdir)\" \ -DSYSTEMD_BINARY_PATH=\"$(rootlibexecdir)/systemd\" \ -DROOTPREFIX=\"$(rootprefix)\" \ -DLIBDIR=\"$(libdir)\" \ -DROOTLIBDIR=\"$(rootlibdir)\" \ -DROOTLIBEXECDIR=\"$(rootlibexecdir)\" \ -I $(top_srcdir)/src ##################################################### dist_noinst_DATA = \ LICENSE.LGPL2.1 \ LICENSE.GPL2 EXTRA_DIST = \ man/bootchart.conf.xml \ man/systemd-bootchart.xml \ man/custom-man.xsl \ man/standard-conf.xml \ man/standard-options.xml \ units/systemd-bootchart.service.in \ tests/run MANPAGES = man/bootchart.conf.5 man/systemd-bootchart.1 MANPAGES_ALIAS = man/bootchart.conf.d.5 if COND_man MAYBE_MANPAGES = $(MANPAGES) $(MANPAGES_ALIAS) endif man_MANS = $(MAYBE_MANPAGES) man/bootchart.conf.d.5: man/bootchart.conf.5 XSLTPROC_FLAGS = \ --nonet \ --xinclude \ --stringparam man.output.quietly 1 \ --stringparam funcsynopsis.style ansi \ --stringparam man.authors.section.enabled 0 \ --stringparam man.copyright.section.enabled 0 \ --stringparam systemd.version $(VERSION) \ --path '$(builddir)/man:$(srcdir)/man' XSLT = $(if $(XSLTPROC), $(XSLTPROC), xsltproc) XSLTPROC_PROCESS_MAN = \ $(AM_V_XSLT)$(XSLT) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-man.xsl $< man/%.1: man/%.xml man/custom-man.xsl $(XSLTPROC_PROCESS_MAN) man/%.5: man/%.xml man/custom-man.xsl $(XSLTPROC_PROCESS_MAN) ##################################################### libutils_la_SOURCES = \ src/alloc-util.c \ src/alloc-util.h \ src/architecture.h \ src/attributes.h \ src/build.h \ src/cgroup-util.c \ src/cgroup-util.h \ src/conf-files.c \ src/conf-files.h \ src/conf-parser.c \ src/conf-parser.h \ src/def.h \ src/dirent-util.c \ src/dirent-util.h \ src/fd-util.c \ src/fd-util.h \ src/fileio.c \ src/fileio.h \ src/formats-util.h \ src/fs-util.c \ src/fs-util.h \ src/hash-funcs.c \ src/hash-funcs.h \ src/hashmap.c \ src/hashmap.h \ src/io-util.c \ src/io-util.h \ src/list.h \ src/log.c \ src/log.h \ src/macro.h \ src/mempool.c \ src/mempool.h \ src/missing.h \ src/parse-util.c \ src/parse-util.h \ src/path-util.c \ src/path-util.h \ src/process-util.c \ src/process-util.h \ src/random-util.c \ src/random-util.h \ src/_sd-common.h \ src/sd-messages.h \ src/set.h \ src/siphash24.c \ src/siphash24.h \ src/stdio-util.h \ src/string-util.c \ src/string-util.h \ src/strv.c \ src/strv.h \ src/strxcpyx.c \ src/strxcpyx.h \ src/terminal-util.c \ src/terminal-util.h \ src/time-util.c \ src/time-util.h \ src/unaligned.h \ src/utf8.c \ src/utf8.h \ src/util.c \ src/util.h libutils_la_CFLAGS = \ $(AM_CFLAGS) \ $(LIBSYSTEMD_CFLAGS) libutils_la_LIBADD = \ $(LIBSYSTEMD_LIBS) noinst_LTLIBRARIES = libutils.la ##################################################### systemd_bootchart_SOURCES = \ src/bootchart.c \ src/bootchart.h \ src/store.c \ src/store.h \ src/svg.c \ src/svg.h systemd_bootchart_LDADD = \ libutils.la ##################################################### TESTS = tests/run substitutions = \ '|rootlibexecdir=$(rootlibexecdir)|' SED_PROCESS = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ $(SED) $(subst '|,-e 's|@,$(subst =,\@|,$(subst |',|g',$(substitutions)))) \ < $< > $@ units/%: units/%.in $(SED_PROCESS) man/%: man/%.in $(SED_PROCESS) rootlibexec_PROGRAMS = systemd-bootchart dist_pkgsysconf_DATA = src/bootchart.conf nodist_systemunit_DATA = units/systemd-bootchart.service in_files = $(filter %.in,$(EXTRA_DIST)) CLEANFILES = \ $(MANPAGES) $(MANPAGES_ALIAS) \ $(pkgconfigdata_DATA) \ $(pkgconfiglib_DATA) \ $(in_files:.in=) install-exec-hook: $(INSTALL_EXEC_HOOKS) uninstall-hook: $(UNINSTALL_DATA_HOOKS) $(UNINSTALL_EXEC_HOOKS) install-data-hook: $(INSTALL_DATA_HOOKS) .PHONY: git-tag git-tag: git tag -s "v$(VERSION)" -m "systemd $(VERSION)" .PHONY: git-tar git-tar: git archive --format=tar --prefix=systemd-$(VERSION)/ HEAD | xz > systemd-$(VERSION).tar.xz systemd-bootchart-233/README000066400000000000000000000002511315600604400157130ustar00rootroot00000000000000For systemd-bootchart, several proc debug interfaces are required in the kernel config: CONFIG_SCHEDSTATS below is optional, for additional info: CONFIG_SCHED_DEBUG systemd-bootchart-233/TODO000066400000000000000000000002511315600604400155230ustar00rootroot00000000000000- plot per-process IO utilization - group processes based on service association (cgroups) - document initcall_debug - kernel cmdline "bootchart" option for simplicity? systemd-bootchart-233/autogen.sh000077500000000000000000000036201315600604400170370ustar00rootroot00000000000000#!/bin/sh # This file is part of systemd-journal-remote. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # systemd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . set -e oldpwd=$(pwd) topdir=$(dirname $0) cd $topdir if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then # This part is allowed to fail cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ chmod +x .git/hooks/pre-commit && \ echo "Activated pre-commit hook." || : fi intltoolize --force --automake autoreconf --force --install --symlink libdir() { echo $(cd "$1/$(gcc -print-multi-os-directory)"; pwd) } args="\ --sysconfdir=/etc \ --localstatedir=/var \ --libdir=$(libdir /usr/lib) \ " if [ -f "$topdir/.config.args" ]; then args="$args $(cat $topdir/.config.args)" fi if [ ! -L /bin ]; then args="$args \ --with-rootprefix=/ \ --with-rootlibdir=$(libdir /lib) \ " fi cd $oldpwd if [ "x$1" = "xc" ]; then $topdir/configure CFLAGS='-g -O0 -ftrapv' $args make clean else echo echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo echo "$topdir/configure CFLAGS='-g -O0 -ftrapv' $args" echo fi systemd-bootchart-233/configure.ac000066400000000000000000000153411315600604400173270ustar00rootroot00000000000000# # This file is part of systemd-bootchart. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # systemd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . AC_PREREQ([2.64]) AC_INIT([systemd-bootchart], [233], [http://github.com/systemd/systemd-bootchart/issues], [systemd-bootchart], [http://github.com/systemd/systemd-bootchart/]) AC_CONFIG_SRCDIR([src/bootchart.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_USE_SYSTEM_EXTENSIONS AC_SYS_LARGEFILE AC_PREFIX_DEFAULT([/usr]) AM_MAINTAINER_MODE([enable]) AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects parallel-tests]) AM_SILENT_RULES([yes]) AC_CANONICAL_HOST AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.]) LT_PREREQ(2.2) LT_INIT([disable-static]) AC_PROG_CC_C99 SET_ARCH(X86_64, x86_64*) SET_ARCH(IA32, i*86*) SET_ARCH(MIPS, mips*) SET_ARCH(AARCH64, aarch64*) AC_CHECK_SIZEOF(pid_t) AC_CHECK_SIZEOF(uid_t) AC_CHECK_SIZEOF(gid_t) AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(dev_t) AC_CHECK_SIZEOF(rlim_t,,[ #include #include ]) AC_CHECK_DECLS([gettid, getrandom], [], [], [[ #include #include #include #include ]]) AC_ARG_WITH(libsystemd, AS_HELP_STRING([--without-libsystemd], [Disable use of libsystemd for journal output]), [], [with_libsystemd=yes]) AS_IF([test "x$with_libsystemd" != xno], [PKG_CHECK_MODULES(LIBSYSTEMD, [libsystemd >= 221], [AC_DEFINE([HAVE_LIBSYSTEMD],[1],[Define if you have libsystemd])], [AC_MSG_ERROR([*** libsystemd library not found])] )] ) CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ -pipe \ -Wall \ -Wextra \ -Wundef \ "-Wformat=2 -Wformat-security -Wformat-nonliteral" \ -Wlogical-op \ -Wmissing-include-dirs \ -Wold-style-definition \ -Wpointer-arith \ -Winit-self \ -Wdeclaration-after-statement \ -Wfloat-equal \ -Wsuggest-attribute=noreturn \ -Werror=missing-prototypes \ -Werror=implicit-function-declaration \ -Werror=missing-declarations \ -Werror=return-type \ -Werror=shadow \ -Wstrict-prototypes \ -Wredundant-decls \ -Wmissing-noreturn \ -Wshadow \ -Wendif-labels \ -Wstrict-aliasing=2 \ -Wwrite-strings \ -Wno-unused-parameter \ -Wno-missing-field-initializers \ -Wno-unused-result \ -Wno-format-signedness \ -Werror=overflow \ -Wdate-time \ -Wnested-externs \ -ffast-math \ -fno-common \ -fdiagnostics-show-option \ -fno-strict-aliasing \ -fvisibility=hidden \ -fstack-protector \ -fstack-protector-strong \ -fPIE \ --param=ssp-buffer-size=4]) AS_CASE([$CC], [*clang*], [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\ -Wno-typedef-redefinition \ -Wno-gnu-variable-sized-type-not-at-end \ ])]) AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ -flto -ffat-lto-objects])], [AC_MSG_RESULT([skipping -flto, optimization not enabled])]) AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags") AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\ -Wp,-D_FORTIFY_SOURCE=2])], [AC_MSG_RESULT([skipping -D_FORTIFY_SOURCE, optimization not enabled])]) AC_SUBST([OUR_CPPFLAGS], "$with_cppflags $sanitizer_cppflags") AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], [CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ -Wl,--gc-sections])], [AC_MSG_RESULT([skipping --gc-sections, optimization not enabled])]) AC_SUBST([OUR_CFLAGS], "$with_ldflags $sanitizer_cflags") AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ -ffunction-sections -fdata-sections])], [AC_MSG_RESULT([skipping -ffunction/data-section, optimization not enabled])]) AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags") CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ -Wl,--as-needed \ -Wl,--no-undefined \ -Wl,-z,relro \ -Wl,-z,now \ -pie]) AC_SUBST([OUR_LDFLAGS], "$with_ldflags $sanitizer_ldflags") AC_ARG_WITH([rootprefix], AS_HELP_STRING([--with-rootprefix=DIR], [rootfs directory prefix for config files and binaries necessary for boot]), [], [with_rootprefix=${ac_default_prefix}]) # --with-rootprefix= (empty) should default to "/" but AX_NORMALIZE_PATH # defaults those to ".", solve that here for now until we can find a suitable # fix for AX_NORMALIZE_PATH upstream at autoconf-archive. # See: https://github.com/systemd/systemd/issues/54 if test "x${with_rootprefix}" = "x"; then with_rootprefix="/" fi AX_NORMALIZE_PATH([with_rootprefix]) AC_ARG_WITH([rootlibdir], AS_HELP_STRING([--with-rootlibdir=DIR], [Root directory for libraries necessary for boot]), [], [with_rootlibdir=${libdir}]) AC_SUBST([rootprefix], [$with_rootprefix]) AC_SUBST([rootlibdir], [$with_rootlibdir]) AC_ARG_ENABLE([man], AS_HELP_STRING([--disable-man],[Build the man pages (default: yes)]), [build_man=$enableval], [build_man=yes]) AC_PATH_PROG([XSLTPROC], [xsltproc]) AS_IF([test -z "$XSLTPROC" -a "$build_man" = "yes"], [AC_MSG_ERROR([*** xsltproc is required for man pages])]) AM_CONDITIONAL([COND_man],[test "$build_man" = "yes"]) AC_CONFIG_FILES([ Makefile ]) AC_OUTPUT AC_MSG_RESULT([ $PACKAGE_NAME $VERSION prefix: ${prefix} sysconf dir: ${sysconfdir} datarootdir: ${datarootdir} includedir: ${includedir} lib dir: ${libdir} rootlib dir: ${with_rootlibdir} CFLAGS: ${OUR_CFLAGS} ${CFLAGS} CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} ]) systemd-bootchart-233/m4/000077500000000000000000000000001315600604400153555ustar00rootroot00000000000000systemd-bootchart-233/m4/.gitignore000066400000000000000000000001131315600604400173400ustar00rootroot00000000000000intltool.m4 libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4 systemd-bootchart-233/m4/arch.m4000066400000000000000000000004351315600604400165360ustar00rootroot00000000000000 dnl SET_ARCH(ARCHNAME, PATTERN) dnl dnl Define ARCH_ condition if the pattern match with the current dnl architecture dnl AC_DEFUN([SET_ARCH], [ cpu_$1=false case "$host" in $2) cpu_$1=true ;; esac AM_CONDITIONAL(AS_TR_CPP(ARCH_$1), [test "x$cpu_$1" = xtrue]) ]) systemd-bootchart-233/m4/attributes.m4000066400000000000000000000240211315600604400200040ustar00rootroot00000000000000dnl Macros to check the presence of generic (non-typed) symbols. dnl Copyright (c) 2006-2008 Diego Pettenò dnl Copyright (c) 2006-2008 xine project dnl Copyright (c) 2012 Lucas De Marchi dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2, or (at your option) dnl any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA dnl 02110-1301, USA. dnl dnl As a special exception, the copyright owners of the dnl macro gives unlimited permission to copy, distribute and modify the dnl configure scripts that are the output of Autoconf when processing the dnl Macro. You need not follow the terms of the GNU General Public dnl License when using or distributing such scripts, even though portions dnl of the text of the Macro appear in them. The GNU General Public dnl License (GPL) does govern all other use of the material that dnl constitutes the Autoconf Macro. dnl dnl This special exception to the GPL applies to versions of the dnl Autoconf Macro released by this project. When you make and dnl distribute a modified version of the Autoconf Macro, you may extend dnl this special exception to the GPL to apply to your modified version as dnl well. dnl Check if FLAG in ENV-VAR is supported by compiler and append it dnl to WHERE-TO-APPEND variable. Note that we invert -Wno-* checks to dnl -W* as gcc cannot test for negated warnings. If a C snippet is passed, dnl use it, otherwise use a simple main() definition that just returns 0. dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG], [C-SNIPPET]) AC_DEFUN([CC_CHECK_FLAG_APPEND], [ AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], AS_TR_SH([cc_cv_$2_$3]), [eval "AS_TR_SH([cc_save_$2])='${$2}'" eval "AS_TR_SH([$2])='${cc_save_$2} -Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" AC_LINK_IFELSE([AC_LANG_SOURCE(ifelse([$4], [], [int main(void) { return 0; } ], [$4]))], [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) eval "AS_TR_SH([$2])='$cc_save_$2'"]) AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], [eval "$1='${$1} $3'"]) ]) dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2], [C-SNIPPET]) AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ for flag in [$3]; do CC_CHECK_FLAG_APPEND([$1], [$2], $flag, [$4]) done ]) dnl Check if the flag is supported by linker (cacheable) dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) AC_DEFUN([CC_CHECK_LDFLAGS], [ AC_CACHE_CHECK([if $CC supports $1 flag], AS_TR_SH([cc_cv_ldflags_$1]), [ac_save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $1" AC_LINK_IFELSE([int main() { return 1; }], [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) LDFLAGS="$ac_save_LDFLAGS" ]) AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], [$2], [$3]) ]) dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for dnl the current linker to avoid undefined references in a shared object. AC_DEFUN([CC_NOUNDEFINED], [ dnl We check $host for which systems to enable this for. AC_REQUIRE([AC_CANONICAL_HOST]) case $host in dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads dnl are requested, as different implementations are present; to avoid problems dnl use -Wl,-z,defs only for those platform not behaving this way. *-freebsd* | *-openbsd*) ;; *) dnl First of all check for the --no-undefined variant of GNU ld. This allows dnl for a much more readable command line, so that people can understand what dnl it does without going to look for what the heck -z defs does. for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) break done ;; esac AC_SUBST([LDFLAGS_NOUNDEFINED]) ]) dnl Check for a -Werror flag or equivalent. -Werror is the GCC dnl and ICC flag that tells the compiler to treat all the warnings dnl as fatal. We usually need this option to make sure that some dnl constructs (like attributes) are not simply ignored. dnl dnl Other compilers don't support -Werror per se, but they support dnl an equivalent flag: dnl - Sun Studio compiler supports -errwarn=%all AC_DEFUN([CC_CHECK_WERROR], [ AC_CACHE_CHECK( [for $CC way to treat warnings as errors], [cc_cv_werror], [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) ]) ]) AC_DEFUN([CC_CHECK_ATTRIBUTE], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], AS_TR_SH([cc_cv_attribute_$1]), [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) CFLAGS="$ac_save_CFLAGS" ]) AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], [AC_DEFINE( AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] ) $4], [$5]) ]) AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ CC_CHECK_ATTRIBUTE( [constructor],, [void __attribute__((constructor)) ctor() { int a; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ CC_CHECK_ATTRIBUTE( [format], [format(printf, n, n)], [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ CC_CHECK_ATTRIBUTE( [format_arg], [format_arg(printf)], [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ CC_CHECK_ATTRIBUTE( [visibility_$1], [visibility("$1")], [void __attribute__((visibility("$1"))) $1_function() { }], [$2], [$3]) ]) AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ CC_CHECK_ATTRIBUTE( [nonnull], [nonnull()], [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ CC_CHECK_ATTRIBUTE( [unused], , [void some_function(void *foo, __attribute__((unused)) void *bar);], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ CC_CHECK_ATTRIBUTE( [sentinel], , [void some_function(void *foo, ...) __attribute__((sentinel));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ CC_CHECK_ATTRIBUTE( [deprecated], , [void some_function(void *foo, ...) __attribute__((deprecated));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ CC_CHECK_ATTRIBUTE( [alias], [weak, alias], [void other_function(void *foo) { } void some_function(void *foo) __attribute__((weak, alias("other_function")));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ CC_CHECK_ATTRIBUTE( [malloc], , [void * __attribute__((malloc)) my_alloc(int n);], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_PACKED], [ CC_CHECK_ATTRIBUTE( [packed], , [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], [$1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_CONST], [ CC_CHECK_ATTRIBUTE( [const], , [int __attribute__((const)) twopow(int n) { return 1 << n; } ], [$1], [$2]) ]) AC_DEFUN([CC_FLAG_VISIBILITY], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], [cc_cv_flag_visibility], [cc_flag_visibility_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], cc_cv_flag_visibility='yes', cc_cv_flag_visibility='no') CFLAGS="$cc_flag_visibility_save_CFLAGS"]) AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, [Define this if the compiler supports the -fvisibility flag]) $1], [$2]) ]) AC_DEFUN([CC_FUNC_EXPECT], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if compiler has __builtin_expect function], [cc_cv_func_expect], [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" AC_COMPILE_IFELSE([AC_LANG_SOURCE( [int some_function() { int a = 3; return (int)__builtin_expect(a, 3); }])], [cc_cv_func_expect=yes], [cc_cv_func_expect=no]) CFLAGS="$ac_save_CFLAGS" ]) AS_IF([test "x$cc_cv_func_expect" = "xyes"], [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, [Define this if the compiler supports __builtin_expect() function]) $1], [$2]) ]) AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], [cc_cv_attribute_aligned], [ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" for cc_attribute_align_try in 64 32 16 8 4 2; do AC_COMPILE_IFELSE([AC_LANG_SOURCE([ int main() { static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; return c; }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) done CFLAGS="$ac_save_CFLAGS" ]) if test "x$cc_cv_attribute_aligned" != "x"; then AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], [Define the highest alignment supported]) fi ]) systemd-bootchart-233/m4/ax_normalize_path.m4000066400000000000000000000113401315600604400213220ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_normalize_path.html # =========================================================================== # # SYNOPSIS # # AX_NORMALIZE_PATH(VARNAME, [REFERENCE_STRING]) # # DESCRIPTION # # Perform some cleanups on the value of $VARNAME (interpreted as a path): # # - empty paths are changed to '.' # - trailing slashes are removed # - repeated slashes are squeezed except a leading doubled slash '//' # (which might indicate a networked disk on some OS). # # REFERENCE_STRING is used to turn '/' into '\' and vice-versa: if # REFERENCE_STRING contains some backslashes, all slashes and backslashes # are turned into backslashes, otherwise they are all turned into slashes. # # This makes processing of DOS filenames quite easier, because you can # turn a filename to the Unix notation, make your processing, and turn it # back to original notation. # # filename='A:\FOO\\BAR\' # old_filename="$filename" # # Switch to the unix notation # AX_NORMALIZE_PATH([filename], ["/"]) # # now we have $filename = 'A:/FOO/BAR' and we can process it as if # # it was a Unix path. For instance let's say that you want # # to append '/subpath': # filename="$filename/subpath" # # finally switch back to the original notation # AX_NORMALIZE_PATH([filename], ["$old_filename"]) # # now $filename equals to 'A:\FOO\BAR\subpath' # # One good reason to make all path processing with the unix convention is # that backslashes have a special meaning in many cases. For instance # # expr 'A:\FOO' : 'A:\Foo' # # will return 0 because the second argument is a regex in which # backslashes have to be backslashed. In other words, to have the two # strings to match you should write this instead: # # expr 'A:\Foo' : 'A:\\Foo' # # Such behavior makes DOS filenames extremely unpleasant to work with. So # temporary turn your paths to the Unix notation, and revert them to the # original notation after the processing. See the macro # AX_COMPUTE_RELATIVE_PATHS for a concrete example of this. # # REFERENCE_STRING defaults to $VARIABLE, this means that slashes will be # converted to backslashes if $VARIABLE already contains some backslashes # (see $thirddir below). # # firstdir='/usr/local//share' # seconddir='C:\Program Files\\' # thirddir='C:\home/usr/' # AX_NORMALIZE_PATH([firstdir]) # AX_NORMALIZE_PATH([seconddir]) # AX_NORMALIZE_PATH([thirddir]) # # $firstdir = '/usr/local/share' # # $seconddir = 'C:\Program Files' # # $thirddir = 'C:\home\usr' # # LICENSE # # Copyright (c) 2008 Alexandre Duret-Lutz # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 5 AU_ALIAS([ADL_NORMALIZE_PATH], [AX_NORMALIZE_PATH]) AC_DEFUN([AX_NORMALIZE_PATH], [case ":[$]$1:" in # change empty paths to '.' ::) $1='.' ;; # strip trailing slashes :*[[\\/]]:) $1=`echo "[$]$1" | sed 's,[[\\/]]*[$],,'` ;; :*:) ;; esac # squeze repeated slashes case ifelse($2,,"[$]$1",$2) in # if the path contains any backslashes, turn slashes into backslashes *\\*) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1\\\\,g'` ;; # if the path contains slashes, also turn backslashes into slashes *) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1/,g'` ;; esac]) systemd-bootchart-233/man/000077500000000000000000000000001315600604400156105ustar00rootroot00000000000000systemd-bootchart-233/man/.gitignore000066400000000000000000000001231315600604400175740ustar00rootroot00000000000000/systemd.directives.xml /systemd.index.xml /*.[13578] /*.html /custom-entities.ent systemd-bootchart-233/man/bootchart.conf.xml000066400000000000000000000144761315600604400212570ustar00rootroot00000000000000 bootchart.conf systemd Developer Auke Kok auke-jan.h.kok@intel.com bootchart.conf 5 bootchart.conf bootchart.conf.d Boot performance analysis graphing tool configuration files /etc/systemd/bootchart.conf /etc/systemd/bootchart.conf.d/*.conf /run/systemd/bootchart.conf.d/*.conf /usr/lib/systemd/bootchart.conf.d/*.conf Description When starting, systemd-bootchart will read the configuration file /etc/systemd/bootchart.conf, followed by the files in the bootchart.conf.d directories. These configuration files determine logging parameters and graph output. Options Samples=500 Configure the amount of samples to record in total before bootchart exits. Each sample will record at intervals defined by Frequency=. Frequency=25 Configure the sample log frequency. This can be a fractional number, but must be larger than 0.0. Most systems can cope with values under 25-50 without impacting boot time severely. Relative=no Configures whether the left axis of the output graph equals time=0.0 (CLOCK_MONOTONIC start). This is useful for using bootchart at post-boot time to profile an already booted system, otherwise the graph would become extremely large. If set to yes, the horizontal axis starts at the first recorded sample instead of time=0.0. Filter=no Configures whether the resulting graph should omit tasks that did not contribute significantly to the boot. Processes that are too short-lived (only seen in one sample) or that do not consume any significant CPU time (less than 0.001sec) will not be displayed in the output graph. Output=[path] Configures the output directory for writing the graphs. By default, bootchart writes the graphs to /run/log. Init=[path] Configures bootchart to run a non-standard binary instead of /usr/lib/systemd/systemd. This option is only relevant if bootchart was invoked from the kernel command line with init=/usr/lib/systemd/systemd-bootchart. PlotMemoryUsage=no If set to yes, enables logging and graphing of processes' PSS memory consumption. PlotEntropyGraph=no If set to yes, enables logging and graphing of the kernel random entropy pool size. ScaleX=100 Horizontal scaling factor for all variable graph components. ScaleY=20 Vertical scaling factor for all variable graph components. ControlGroup=no Display process control group. Cmdline=no Display the full command line of each process. See Also systemd-bootchart1, systemd.directives7 systemd-bootchart-233/man/custom-man.xsl000066400000000000000000000042121315600604400204220ustar00rootroot00000000000000 .TH " " " " "" "systemd " " " " " systemd-bootchart-233/man/standard-conf.xml000066400000000000000000000074751315600604400210720ustar00rootroot00000000000000 Configuration Directories and Precedence Configuration files are read from directories in /etc/, /run/, and /usr/lib/, in order of precedence. Each configuration file in these configuration directories shall be named in the style of filename.conf. Files in /etc/ override files with the same name in /run/ and /usr/lib/. Files in /run/ override files with the same name in /usr/lib/. Packages should install their configuration files in /usr/lib/. Files in /etc/ are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. All configuration files are sorted by their filename in lexicographic order, regardless of which of the directories they reside in. If multiple files specify the same option, the entry in the file with the lexicographically latest name will take precedence. It is recommended to prefix all filenames with a two-digit number and a dash, to simplify the ordering of the files. If the administrator wants to disable a configuration file supplied by the vendor, the recommended way is to place a symlink to /dev/null in the configuration directory in /etc/, with the same filename as the vendor configuration file. If the vendor configuration file is included in the initrd image, the image has to be regenerated. Configuration Directories and Precedence The default configuration is defined during compilation, so a configuration file is only needed when it is necessary to deviate from those defaults. By default, the configuration file in /etc/systemd/ contains commented out entries showing the defaults as a guide to the administrator. This file can be edited to create local overrides. When packages need to customize the configuration, they can install configuration snippets in /usr/lib/systemd/*.conf.d/. Files in /etc/ are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. The main configuration file is read before any of the configuration directories, and has the lowest precedence; entries in a file in any configuration directory override entries in the single configuration file. Files in the *.conf.d/ configuration subdirectories are sorted by their filename in lexicographic order, regardless of which of the subdirectories they reside in. If multiple files specify the same option, the entry in the file with the lexicographically latest name takes precedence. It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering of the files. To disable a configuration file supplied by the vendor, the recommended way is to place a symlink to /dev/null in the configuration directory in /etc/, with the same filename as the vendor configuration file. systemd-bootchart-233/man/standard-options.xml000066400000000000000000000020671315600604400216300ustar00rootroot00000000000000 Print a short help text and exit. Print a short version string and exit. Do not pipe output into a pager. Do not print the legend, i.e. column headers and the footer with hints. systemd-bootchart-233/man/systemd-bootchart.xml000066400000000000000000000305571315600604400220170ustar00rootroot00000000000000 systemd-bootchart systemd Developer Auke Kok auke-jan.h.kok@intel.com systemd-bootchart 1 systemd-bootchart Boot performance graphing tool Description systemd-bootchart is a tool, usually run at system startup, that collects the CPU load, disk load, memory usage, as well as per-process information from a running system. Collected results are output as an SVG graph. Normally, systemd-bootchart is invoked by the kernel by passing on the kernel command line, adding to collect data on kernel init threads. systemd-bootchart will then fork the real init off to resume normal system startup, while monitoring and logging startup information in the background. After collecting a certain amount of data (usually 15-30 seconds, default 20 s) the logging stops and a graph is generated from the logged information. This graph contains vital clues as to which resources are being used, in which order, and where possible problems exist in the startup sequence of the system. It is essentially a more detailed version of the systemd-analyze plot function. Of course, bootchart can also be used at any moment in time to collect and graph some data for an amount of time. It is recommended to use the switch in this case. Bootchart does not require root privileges, and will happily run as a normal user. Bootchart graphs are by default written time-stamped in /run/log and saved to the journal with MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518. Journal field BOOTCHART= contains the bootchart in SVG format. Invocation systemd-bootchart can be invoked in several different ways: Kernel invocation The kernel can invoke systemd-bootchart instead of the init process. In turn, systemd-bootchart will invoke /usr/lib/systemd/systemd. Data will be collected on kernel init threads and also processes including the services started by systemd. systemd unit A unit file is provided, systemd-bootchart.service. If enabled when the system starts it will collect data on processes including the services started by systemd. Started as a standalone program One can execute systemd-bootchart as normal application from the command line. In this mode it is highly recommended to pass the flag in order to not graph the time elapsed since boot and before systemd-bootchart was started, as it may result in extremely large graphs. The time elapsed since boot might also include any time that the system was suspended. Options These options can also be set in the /etc/systemd/bootchart.conf file. See bootchart.conf5. Specify the number of samples, N, to record. Samples will be recorded at intervals defined with . Specify the sample log frequency, a positive real f, in Hz. Most systems can cope with values up to 25-50 without creating too much overhead. Use relative times instead of absolute times. This is useful for using bootchart at post-boot time to profile an already booted system. Without this option the graph would become extremely large. If set, the horizontal axis starts at the first recorded sample instead of time 0.0. Disable filtering of tasks that did not contribute significantly to the boot. Processes that are too short-lived (only seen in one sample) or that do not consume any significant CPU time (less than 0.001 s) will not be displayed in the output graph. Display the full command line with arguments of processes, instead of only the process name. Display process control group Specify the output directory for the graphs. By default, bootchart writes the graphs to /run/log. Use this init binary. Defaults to /usr/lib/systemd/systemd. Enable logging and graphing of processes' PSS (Proportional Set Size) memory consumption. See filesystems/proc.txt in the kernel documentation for an explanation of this field. Enable logging and graphing of the kernel random entropy pool size. Horizontal scaling factor for all variable graph components. Vertical scaling factor for all variable graph components. Output systemd-bootchart generates SVG graphs. In order to render those on a graphical display any SVG capable viewer can be used. It should be noted that the SVG render engines in most browsers (including Chrome and Firefox) are many times faster than dedicated graphical applications like Gimp and Inkscape. Just point your browser at ! History This version of bootchart was implemented from scratch, but is inspired by former bootchart incantations: Original bash The original bash/shell code implemented bootchart. This version created a compressed tarball for processing with external applications. This version did not graph anything, only generated data. Ubuntu C Implementation This version replaced the shell version with a fast and efficient data logger, but also did not graph the data. Java bootchart This was the original graphing application for charting the data, written in java. pybootchartgui.py pybootchart created a graph from the data collected by either the bash or C version. The version of bootchart you are using now combines both the data collection and the charting into a single application, making it more efficient and simpler. There are no longer any timing issues with the data collector and the grapher, as the graphing cannot be run until the data has been collected. Also, the data kept in memory is reduced to the absolute minimum needed. See Also bootchart.conf5 Bugs systemd-bootchart does not get the model information for the hard drive unless the root device is specified with root=/dev/sdxY. Using UUIDs or PARTUUIDs will boot fine, but the hard drive model will not be added to the chart. For bugs, please contact the author and current maintainer: Auke Kok auke-jan.h.kok@intel.com systemd-bootchart-233/po/000077500000000000000000000000001315600604400154535ustar00rootroot00000000000000systemd-bootchart-233/po/.gitignore000066400000000000000000000001121315600604400174350ustar00rootroot00000000000000POTFILES Makefile.in.in .intltool-merge-cache Makefile systemd.pot /*.gmo systemd-bootchart-233/src/000077500000000000000000000000001315600604400156245ustar00rootroot00000000000000systemd-bootchart-233/src/Makefile000066400000000000000000000016761315600604400172760ustar00rootroot00000000000000# This file is part of systemd. # # Copyright 2010 Lennart Poettering # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # systemd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . # This file is a dirty trick to simplify compilation from within # emacs. This file is not intended to be distributed. So, don't touch # it, even better ignore it! all: $(MAKE) -C .. clean: $(MAKE) -C .. clean .PHONY: all clean systemd-bootchart-233/src/_sd-common.h000066400000000000000000000051301315600604400200270ustar00rootroot00000000000000#ifndef foosdcommonhfoo #define foosdcommonhfoo /*** This file is part of systemd. Copyright 2013 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ /* This is a private header; never even think of including this directly! */ #if __INCLUDE_LEVEL__ <= 1 #error "Do not include _sd-common.h directly; it is a private header." #endif #ifndef _sd_printf_ # if __GNUC__ >= 4 # define _sd_printf_(a,b) __attribute__ ((format (printf, a, b))) # else # define _sd_printf_(a,b) # endif #endif #ifndef _sd_sentinel_ # define _sd_sentinel_ __attribute__((sentinel)) #endif #ifndef _sd_packed_ # define _sd_packed_ __attribute__((packed)) #endif #ifndef _sd_pure_ # define _sd_pure_ __attribute__((pure)) #endif #ifndef _SD_STRINGIFY # define _SD_XSTRINGIFY(x) #x # define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x) #endif #ifndef _SD_BEGIN_DECLARATIONS # ifdef __cplusplus # define _SD_BEGIN_DECLARATIONS \ extern "C" { \ struct _sd_useless_struct_to_allow_trailing_semicolon_ # else # define _SD_BEGIN_DECLARATIONS \ struct _sd_useless_struct_to_allow_trailing_semicolon_ # endif #endif #ifndef _SD_END_DECLARATIONS # ifdef __cplusplus # define _SD_END_DECLARATIONS \ } \ struct _sd_useless_cpp_struct_to_allow_trailing_semicolon_ # else # define _SD_END_DECLARATIONS \ struct _sd_useless_struct_to_allow_trailing_semicolon_ # endif #endif #define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ static inline void func##p(type **p) { \ if (*p) \ func(*p); \ } \ struct _sd_useless_struct_to_allow_trailing_semicolon_ #endif systemd-bootchart-233/src/alloc-util.c000066400000000000000000000027561315600604400200470ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include "alloc-util.h" #include "macro.h" void* memdup(const void *p, size_t l) { void *r; assert(p); r = malloc(l); if (!r) return NULL; memcpy(r, p, l); return r; } void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { size_t a, newalloc; void *q; assert(p); assert(allocated); if (*allocated >= need) return *p; newalloc = MAX(need * 2, 64u / size); a = newalloc * size; /* check for overflows */ if (a < size * need) return NULL; q = realloc(*p, a); if (!q) return NULL; *p = q; *allocated = newalloc; return q; } systemd-bootchart-233/src/alloc-util.h000066400000000000000000000070311315600604400200430ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) #define new0(t, n) ((t*) calloc((n), sizeof(t))) #define newa(t, n) ((t*) alloca(sizeof(t)*(n))) #define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) #define malloc0(n) (calloc(1, (n))) static inline void *mfree(void *memory) { free(memory); return NULL; } void* memdup(const void *p, size_t l) _alloc_(2); static inline void freep(void *p) { free(*(void**) p); } #define _cleanup_free_ _cleanup_(freep) _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) return NULL; return malloc(a * b); } _alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) return NULL; return realloc(p, a * b); } _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) return NULL; return memdup(p, a * b); } void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); #define GREEDY_REALLOC(array, allocated, need) \ greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) #define alloca0(n) \ ({ \ char *_new_; \ size_t _len_ = n; \ _new_ = alloca(_len_); \ (void *) memset(_new_, 0, _len_); \ }) /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ #define alloca_align(size, align) \ ({ \ void *_ptr_; \ size_t _mask_ = (align) - 1; \ _ptr_ = alloca((size) + _mask_); \ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ }) #define alloca0_align(size, align) \ ({ \ void *_new_; \ size_t _size_ = (size); \ _new_ = alloca_align(_size_, (align)); \ (void*)memset(_new_, 0, _size_); \ }) systemd-bootchart-233/src/architecture.h000066400000000000000000000152141315600604400204620ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2014 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include "macro.h" #include "util.h" /* A cleaned up architecture definition. We don't want to get lost in * processor features, models, generations or even ABIs. Hence we * focus on general family, and distinguish word width and * endianness. */ enum { ARCHITECTURE_X86 = 0, ARCHITECTURE_X86_64, ARCHITECTURE_PPC, ARCHITECTURE_PPC_LE, ARCHITECTURE_PPC64, ARCHITECTURE_PPC64_LE, ARCHITECTURE_IA64, ARCHITECTURE_PARISC, ARCHITECTURE_PARISC64, ARCHITECTURE_S390, ARCHITECTURE_S390X, ARCHITECTURE_SPARC, ARCHITECTURE_SPARC64, ARCHITECTURE_MIPS, ARCHITECTURE_MIPS_LE, ARCHITECTURE_MIPS64, ARCHITECTURE_MIPS64_LE, ARCHITECTURE_ALPHA, ARCHITECTURE_ARM, ARCHITECTURE_ARM_BE, ARCHITECTURE_ARM64, ARCHITECTURE_ARM64_BE, ARCHITECTURE_SH, ARCHITECTURE_SH64, ARCHITECTURE_M68K, ARCHITECTURE_TILEGX, ARCHITECTURE_CRIS, _ARCHITECTURE_MAX, _ARCHITECTURE_INVALID = -1 }; int uname_architecture(void); /* * LIB_ARCH_TUPLE should resolve to the local library path * architecture tuple systemd is built for, according to the Debian * tuple list: * * https://wiki.debian.org/Multiarch/Tuples * * This is used in library search paths that should understand * Debian's paths on all distributions. */ #if defined(__x86_64__) # define native_architecture() ARCHITECTURE_X86_64 # define LIB_ARCH_TUPLE "x86_64-linux-gnu" # define PROC_CPUINFO_MODEL "model name" #elif defined(__i386__) # define native_architecture() ARCHITECTURE_X86 # define LIB_ARCH_TUPLE "i386-linux-gnu" # define PROC_CPUINFO_MODEL "model name" #elif defined(__powerpc64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC64 # define LIB_ARCH_TUPLE "ppc64-linux-gnu" # else # define native_architecture() ARCHITECTURE_PPC64_LE # define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" # endif # define PROC_CPUINFO_MODEL "cpu" #elif defined(__powerpc__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC # define LIB_ARCH_TUPLE "powerpc-linux-gnu" # else # define native_architecture() ARCHITECTURE_PPC_LE # error "Missing LIB_ARCH_TUPLE for PPCLE" # endif # define PROC_CPUINFO_MODEL "cpu" #elif defined(__ia64__) # define native_architecture() ARCHITECTURE_IA64 # define LIB_ARCH_TUPLE "ia64-linux-gnu" #elif defined(__hppa64__) # define native_architecture() ARCHITECTURE_PARISC64 # error "Missing LIB_ARCH_TUPLE for HPPA64" # define PROC_CPUINFO_MODEL "cpu" #elif defined(__hppa__) # define native_architecture() ARCHITECTURE_PARISC # define LIB_ARCH_TUPLE "hppa‑linux‑gnu" # define PROC_CPUINFO_MODEL "cpu" #elif defined(__s390x__) # define native_architecture() ARCHITECTURE_S390X # define LIB_ARCH_TUPLE "s390x-linux-gnu" #elif defined(__s390__) # define native_architecture() ARCHITECTURE_S390 # define LIB_ARCH_TUPLE "s390-linux-gnu" #elif defined(__sparc64__) # define native_architecture() ARCHITECTURE_SPARC64 # define LIB_ARCH_TUPLE "sparc64-linux-gnu" # define PROC_CPUINFO_MODEL "cpu" #elif defined(__sparc__) # define native_architecture() ARCHITECTURE_SPARC # define LIB_ARCH_TUPLE "sparc-linux-gnu" # define PROC_CPUINFO_MODEL "cpu" #elif defined(__mips64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS64 # error "Missing LIB_ARCH_TUPLE for MIPS64" # else # define native_architecture() ARCHITECTURE_MIPS64_LE # error "Missing LIB_ARCH_TUPLE for MIPS64_LE" # endif # define PROC_CPUINFO_MODEL "cpu model" #elif defined(__mips__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS # define LIB_ARCH_TUPLE "mips-linux-gnu" # else # define native_architecture() ARCHITECTURE_MIPS_LE # define LIB_ARCH_TUPLE "mipsel-linux-gnu" # endif # define PROC_CPUINFO_MODEL "cpu model" #elif defined(__alpha__) # define native_architecture() ARCHITECTURE_ALPHA # define LIB_ARCH_TUPLE "alpha-linux-gnu" #elif defined(__aarch64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_ARM64_BE # define LIB_ARCH_TUPLE "aarch64_be-linux-gnu" # else # define native_architecture() ARCHITECTURE_ARM64 # define LIB_ARCH_TUPLE "aarch64-linux-gnu" # endif #elif defined(__arm__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_ARM_BE # if defined(__ARM_EABI__) # if defined(__ARM_PCS_VFP) # define LIB_ARCH_TUPLE "armeb-linux-gnueabihf" # else # define LIB_ARCH_TUPLE "armeb-linux-gnueabi" # endif # else # define LIB_ARCH_TUPLE "armeb-linux-gnu" # endif # else # define native_architecture() ARCHITECTURE_ARM # if defined(__ARM_EABI__) # if defined(__ARM_PCS_VFP) # define LIB_ARCH_TUPLE "arm-linux-gnueabihf" # else # define LIB_ARCH_TUPLE "arm-linux-gnueabi" # endif # else # define LIB_ARCH_TUPLE "arm-linux-gnu" # endif # endif # define PROC_CPUINFO_MODEL "model name" #elif defined(__sh64__) # define native_architecture() ARCHITECTURE_SH64 # error "Missing LIB_ARCH_TUPLE for SH64" #elif defined(__sh__) # define native_architecture() ARCHITECTURE_SH # define LIB_ARCH_TUPLE "sh4-linux-gnu" #elif defined(__m68k__) # define native_architecture() ARCHITECTURE_M68K # define LIB_ARCH_TUPLE "m68k-linux-gnu" #elif defined(__tilegx__) # define native_architecture() ARCHITECTURE_TILEGX # error "Missing LIB_ARCH_TUPLE for TILEGX" #elif defined(__cris__) # define native_architecture() ARCHITECTURE_CRIS # error "Missing LIB_ARCH_TUPLE for CRIS" #else # error "Please register your architecture here!" #endif #ifndef PROC_CPUINFO_MODEL #warning "PROC_CPUINFO_MODEL not defined for your architecture" #define PROC_CPUINFO_MODEL "model name" #endif const char *architecture_to_string(int a) _const_; int architecture_from_string(const char *s) _pure_; systemd-bootchart-233/src/attributes.h000066400000000000000000000030471315600604400201670ustar00rootroot00000000000000#define _printf_(a,b) __attribute__ ((format (printf, a, b))) #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) #define _sentinel_ __attribute__ ((sentinel)) #define _unused_ __attribute__ ((unused)) #define _destructor_ __attribute__ ((destructor)) #define _pure_ __attribute__ ((pure)) #define _const_ __attribute__ ((const)) #define _deprecated_ __attribute__ ((deprecated)) #define _packed_ __attribute__ ((packed)) #define _malloc_ __attribute__ ((malloc)) #define _weak_ __attribute__ ((weak)) #define _likely_(x) (__builtin_expect(!!(x),1)) #define _unlikely_(x) (__builtin_expect(!!(x),0)) #define _public_ __attribute__ ((visibility("default"))) #define _hidden_ __attribute__ ((visibility("hidden"))) #define _weakref_(x) __attribute__((weakref(#x))) #define _alignas_(x) __attribute__((aligned(__alignof(x)))) #define _cleanup_(x) __attribute__((cleanup(x))) /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local /* * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */ #if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) #define thread_local _Thread_local #else #define thread_local __thread #endif #endif /* Define C11 noreturn without and even on older gcc * compiler versions */ #ifndef noreturn #if __STDC_VERSION__ >= 201112L #define noreturn _Noreturn #else #define noreturn __attribute__((noreturn)) #endif #endif systemd-bootchart-233/src/bootchart.c000066400000000000000000000464311315600604400177650ustar00rootroot00000000000000/*** This file is part of systemd. Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ /*** Many thanks to those who contributed ideas and code: - Ziga Mahkovec - Original bootchart author - Anders Norgaard - PyBootchartgui - Michael Meeks - bootchart2 - Scott James Remnant - Ubuntu C-based logger - Arjan van de Ven - for the idea to merge bootgraph.pl functionality ***/ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBSYSTEMD #include #endif #include "alloc-util.h" #include "bootchart.h" #include "conf-parser.h" #include "def.h" #include "fd-util.h" #include "fileio.h" #include "io-util.h" #include "list.h" #include "log.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" #include "store.h" #include "string-util.h" #include "strxcpyx.h" #include "svg.h" #include "time-util.h" static int exiting = 0; #define DEFAULT_SAMPLES_LEN 500 #define DEFAULT_HZ 25.0 #define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */ #define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */ #define DEFAULT_INIT ROOTLIBEXECDIR "/systemd" #define DEFAULT_OUTPUT "/run/log" /* graph defaults */ bool arg_entropy = false; bool arg_initcall = true; bool arg_relative = false; bool arg_filter = true; bool arg_show_cmdline = false; bool arg_show_cgroup = false; bool arg_pss = false; bool arg_percpu = false; int arg_samples_len = DEFAULT_SAMPLES_LEN; /* we record len+1 (1 start sample) */ double arg_hz = DEFAULT_HZ; double arg_scale_x = DEFAULT_SCALE_X; double arg_scale_y = DEFAULT_SCALE_Y; char arg_init_path[PATH_MAX] = DEFAULT_INIT; char arg_output_path[PATH_MAX] = DEFAULT_OUTPUT; static void signal_handler(int sig) { exiting = 1; } #define BOOTCHART_MAX (16*1024*1024) static void parse_conf(void) { char *init = NULL, *output = NULL; const ConfigTableItem items[] = { { "Bootchart", "Samples", config_parse_int, 0, &arg_samples_len }, { "Bootchart", "Frequency", config_parse_double, 0, &arg_hz }, { "Bootchart", "Relative", config_parse_bool, 0, &arg_relative }, { "Bootchart", "Filter", config_parse_bool, 0, &arg_filter }, { "Bootchart", "Output", config_parse_path, 0, &output }, { "Bootchart", "Init", config_parse_path, 0, &init }, { "Bootchart", "PlotMemoryUsage", config_parse_bool, 0, &arg_pss }, { "Bootchart", "PlotEntropyGraph", config_parse_bool, 0, &arg_entropy }, { "Bootchart", "ScaleX", config_parse_double, 0, &arg_scale_x }, { "Bootchart", "ScaleY", config_parse_double, 0, &arg_scale_y }, { "Bootchart", "ControlGroup", config_parse_bool, 0, &arg_show_cgroup }, { "Bootchart", "PerCPU", config_parse_bool, 0, &arg_percpu }, { "Bootchart", "Cmdline", config_parse_bool, 0, &arg_show_cmdline}, { NULL, NULL, NULL, 0, NULL } }; config_parse_many(PKGSYSCONFDIR "/bootchart.conf", CONF_PATHS_NULSTR("systemd/bootchart.conf.d"), NULL, config_item_table_lookup, items, true, NULL); if (init != NULL) strscpy(arg_init_path, sizeof(arg_init_path), init); if (output != NULL) strscpy(arg_output_path, sizeof(arg_output_path), output); } static void help(void) { printf("Usage: %s [OPTIONS]\n\n" "Options:\n" " -r --rel Record time relative to recording\n" " -f --freq=FREQ Sample frequency [%g]\n" " -n --samples=N Stop sampling at [%d] samples\n" " -x --scale-x=N Scale the graph horizontally [%g] \n" " -y --scale-y=N Scale the graph vertically [%g] \n" " -p --pss Enable PSS graph (CPU intensive)\n" " -e --entropy Enable the entropy_avail graph\n" " -o --output=PATH Path to output files [%s]\n" " -i --init=PATH Path to init executable [%s]\n" " -F --no-filter Disable filtering of unimportant or ephemeral processes\n" " -C --cmdline Display full command lines with arguments\n" " -c --control-group Display process control group\n" " --per-cpu Draw each CPU utilization and wait bar also\n" " -h --help Display this message\n\n" "See bootchart.conf for more information.\n", program_invocation_short_name, DEFAULT_HZ, DEFAULT_SAMPLES_LEN, DEFAULT_SCALE_X, DEFAULT_SCALE_Y, DEFAULT_OUTPUT, DEFAULT_INIT); } static int parse_argv(int argc, char *argv[]) { enum { ARG_PERCPU = 0x100, }; static const struct option options[] = { {"rel", no_argument, NULL, 'r' }, {"freq", required_argument, NULL, 'f' }, {"samples", required_argument, NULL, 'n' }, {"pss", no_argument, NULL, 'p' }, {"output", required_argument, NULL, 'o' }, {"init", required_argument, NULL, 'i' }, {"no-filter", no_argument, NULL, 'F' }, {"cmdline", no_argument, NULL, 'C' }, {"control-group", no_argument, NULL, 'c' }, {"help", no_argument, NULL, 'h' }, {"scale-x", required_argument, NULL, 'x' }, {"scale-y", required_argument, NULL, 'y' }, {"entropy", no_argument, NULL, 'e' }, {"per-cpu", no_argument, NULL, ARG_PERCPU}, {} }; int c, r; if (getpid() == 1) opterr = 0; while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0) switch (c) { case 'r': arg_relative = true; break; case 'f': r = safe_atod(optarg, &arg_hz); if (r < 0) log_warning_errno(r, "failed to parse --freq/-f argument '%s': %m", optarg); break; case 'F': arg_filter = false; break; case 'C': arg_show_cmdline = true; break; case 'c': arg_show_cgroup = true; break; case 'n': r = safe_atoi(optarg, &arg_samples_len); if (r < 0) log_warning_errno(r, "failed to parse --samples/-n argument '%s': %m", optarg); break; case 'o': path_kill_slashes(optarg); strscpy(arg_output_path, sizeof(arg_output_path), optarg); break; case 'i': path_kill_slashes(optarg); strscpy(arg_init_path, sizeof(arg_init_path), optarg); break; case 'p': arg_pss = true; break; case 'x': r = safe_atod(optarg, &arg_scale_x); if (r < 0) log_warning_errno(r, "failed to parse --scale-x/-x argument '%s': %m", optarg); break; case 'y': r = safe_atod(optarg, &arg_scale_y); if (r < 0) log_warning_errno(r, "failed to parse --scale-y/-y argument '%s': %m", optarg); break; case 'e': arg_entropy = true; break; case ARG_PERCPU: arg_percpu = true; break; case 'h': help(); return 0; case '?': if (getpid() != 1) return -EINVAL; else return 0; default: assert_not_reached("Unhandled option code."); } if (arg_hz <= 0) { log_error("Frequency needs to be > 0"); return -EINVAL; } return 1; } static int do_journal_append(char *file) { #ifdef HAVE_LIBSYSTEMD _cleanup_free_ char *bootchart_message = NULL; _cleanup_free_ char *bootchart_file = NULL; _cleanup_free_ char *p = NULL; _cleanup_close_ int fd = -1; struct iovec iovec[5]; int r, j = 0; ssize_t n; bootchart_file = strappend("BOOTCHART_FILE=", file); if (!bootchart_file) return log_oom(); IOVEC_SET_STRING(iovec[j++], bootchart_file); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); if (!bootchart_message) return log_oom(); IOVEC_SET_STRING(iovec[j++], bootchart_message); p = malloc(10 + BOOTCHART_MAX); if (!p) return log_oom(); memcpy(p, "BOOTCHART=", 10); fd = open(file, O_RDONLY|O_CLOEXEC); if (fd < 0) return log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file); n = loop_read(fd, p + 10, BOOTCHART_MAX, false); if (n < 0) return log_error_errno(n, "Failed to read bootchart data: %m"); iovec[j].iov_base = p; iovec[j].iov_len = 10 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to send bootchart: %m"); #else (void)file; #endif return 0; } int main(int argc, char *argv[]) { static struct list_sample_data *sampledata; _cleanup_closedir_ DIR *proc = NULL; _cleanup_free_ char *build = NULL; _cleanup_fclose_ FILE *of = NULL; _cleanup_close_ int sysfd = -1; int schfd; struct ps_struct *ps_first; double graph_start; double log_start; double interval; char output_file[PATH_MAX]; char datestr[200]; int pscount = 0; int n_cpus = 0; int overrun = 0; time_t t = 0; int r, samples; struct ps_struct *ps; struct list_sample_data *head; struct sigaction sig = { .sa_handler = signal_handler, }; bool has_procfs = false; parse_conf(); r = parse_argv(argc, argv); if (r < 0) return EXIT_FAILURE; if (r == 0) return EXIT_SUCCESS; /* * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then * fork: * - parent execs executable specified via init_path[] (/usr/lib/systemd/systemd by default) as pid=1 * - child logs data */ if (getpid() == 1) { if (fork()) /* parent */ execl(arg_init_path, arg_init_path, NULL); } argv[0][0] = '@'; schfd = open("/proc/sys/kernel/sched_schedstats", O_WRONLY); if (schfd >= 0) { write(schfd, "1\n", 2); close(schfd); } /* start with empty ps LL */ ps_first = new0(struct ps_struct, 1); if (!ps_first) { log_oom(); return EXIT_FAILURE; } /* handle TERM/INT nicely */ sigaction(SIGHUP, &sig, NULL); interval = (1.0 / arg_hz) * 1000000000.0; if (arg_relative) graph_start = log_start = gettime_ns(); else { struct timespec n; double uptime; clock_gettime(clock_boottime_or_monotonic(), &n); uptime = (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); log_start = gettime_ns(); graph_start = log_start - uptime; } if (graph_start < 0.0) { log_error("Failed to setup graph start time.\n\n" "The system uptime probably includes time that the system was suspended. " "Use --rel to bypass this issue."); return EXIT_FAILURE; } has_procfs = access("/proc/vmstat", F_OK) == 0; LIST_HEAD_INIT(head); /* main program loop */ for (samples = 0; !exiting && samples < arg_samples_len; samples++) { int res; double sample_stop; double elapsed; double timeleft; sampledata = new0(struct list_sample_data, 1); if (sampledata == NULL) { log_oom(); return EXIT_FAILURE; } sampledata->sampletime = gettime_ns(); sampledata->counter = samples; if (sysfd < 0) sysfd = open("/sys", O_RDONLY|O_CLOEXEC); if (!build) { if (parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &build, NULL) == -ENOENT) parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL); } if (!has_procfs) { /* wait for /proc to become available, discarding samples */ has_procfs = access("/proc/vmstat", F_OK) == 0; } else if (proc) { rewinddir(proc); } else { proc = opendir("/proc"); } if (proc) { r = log_sample(proc, samples, ps_first, &sampledata, &pscount, &n_cpus); if (r < 0) return EXIT_FAILURE; } sample_stop = gettime_ns(); elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0; timeleft = interval - elapsed; /* * check if we have not consumed our entire timeslice. If we * do, don't sleep and take a new sample right away. * we'll lose all the missed samples and overrun our total * time */ if (timeleft > 0) { struct timespec req; req.tv_sec = (time_t)(timeleft / 1000000000.0); req.tv_nsec = (long)(timeleft - (req.tv_sec * 1000000000.0)); res = nanosleep(&req, NULL); if (res) { if (errno == EINTR) /* caught signal, probably HUP! */ break; log_error_errno(errno, "nanosleep() failed: %m"); return EXIT_FAILURE; } } else { overrun++; /* calculate how many samples we lost and scrap them */ arg_samples_len -= (int)(-timeleft / interval); } LIST_PREPEND(link, head, sampledata); } /* do some cleanup, close fd's */ ps = ps_first; while (ps->next_running) { ps = ps->next_running; ps->schedstat = safe_close(ps->schedstat); ps->sched = safe_close(ps->sched); ps->smaps = safe_fclose(ps->smaps); } if (!of) { t = time(NULL); r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); assert_se(r > 0); snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); of = fopen(output_file, "we"); } if (!of) { log_error("Error opening output file '%s': %m\n", output_file); return EXIT_FAILURE; } r = svg_do(of, strna(build), head, ps_first, samples, pscount, n_cpus, graph_start, log_start, interval, overrun); if (r < 0) { log_error_errno(r, "Error generating svg file: %m"); return EXIT_FAILURE; } log_info("systemd-bootchart wrote %s\n", output_file); r = do_journal_append(output_file); if (r < 0) return EXIT_FAILURE; /* nitpic cleanups */ ps = ps_first->next_ps; while (ps) { struct ps_struct *old; old = ps; old->sample = ps->first; ps = ps->next_ps; while (old->sample->next) { struct ps_sched_struct *oldsample = old->sample; old->sample = old->sample->next; free(oldsample); } free(old->cgroup); free(old->sample); free(old); } free(ps_first); sampledata = head; while (sampledata->link_next) { struct list_sample_data *old_sampledata = sampledata; sampledata = sampledata->link_next; free(old_sampledata); } free(sampledata); /* don't complain when overrun once, happens most commonly on 1st sample */ if (overrun > 1) log_warning("systemd-bootchart: sample time overrun %i times\n", overrun); return 0; } systemd-bootchart-233/src/bootchart.conf000066400000000000000000000013201315600604400204540ustar00rootroot00000000000000# This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # Entries in this file show the compile time defaults. # You can change settings by editing this file. # Defaults can be restored by simply deleting this file. # # See bootchart.conf(5) for details. [Bootchart] #Samples=500 #Frequency=25 #Relative=no #Filter=yes #Output= #Init=/path/to/init-binary #PlotMemoryUsage=no #PlotEntropyGraph=no #ScaleX=100 #ScaleY=20 #ControlGroup=no #PerCPU=no systemd-bootchart-233/src/bootchart.h000066400000000000000000000062721315600604400177710ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "list.h" #define MAXCPUS 16 #define MAXPIDS 65535 struct block_stat_struct { /* /proc/vmstat pgpgin & pgpgout */ int bi; int bo; }; /* per process, per sample data we will log */ struct ps_sched_struct { /* /proc//schedstat fields 1 & 2 */ double runtime; double waittime; int pss; struct list_sample_data *sampledata; struct ps_sched_struct *next; struct ps_sched_struct *prev; struct ps_sched_struct *cross; /* cross pointer */ struct ps_struct *ps_new; }; struct list_sample_data { double runtime[MAXCPUS]; double waittime[MAXCPUS]; double sampletime; int entropy_avail; struct block_stat_struct blockstat; LIST_FIELDS(struct list_sample_data, link); /* DLL */ int counter; }; /* process info */ struct ps_struct { struct ps_struct *next_ps; /* SLL pointer */ struct ps_struct *next_running; /* currently running */ struct ps_struct *parent; /* ppid ref */ struct ps_struct *children; /* children */ struct ps_struct *next; /* siblings */ /* must match - otherwise it's a new process with same PID */ char name[256]; int pid; int ppid; char *cgroup; /* cache fd's */ int sched; int schedstat; FILE *smaps; /* used to garbage collect running process list*/ bool still_running; /* pointers to first/last seen timestamps */ struct ps_sched_struct *first; struct ps_sched_struct *last; /* records actual start time, may be way before bootchart runs */ double starttime; /* record human readable total cpu time */ double total; /* largest PSS size found */ int pss_max; /* for drawing connection lines later */ double pos_x; double pos_y; struct ps_sched_struct *sample; }; extern bool arg_relative; extern bool arg_filter; extern bool arg_show_cmdline; extern bool arg_show_cgroup; extern bool arg_pss; extern bool arg_entropy; extern bool arg_percpu; extern bool arg_initcall; extern int arg_samples_len; extern double arg_hz; extern double arg_scale_x; extern double arg_scale_y; extern char arg_output_path[PATH_MAX]; extern char arg_init_path[PATH_MAX]; systemd-bootchart-233/src/build.h000066400000000000000000000077451315600604400171110ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #ifdef HAVE_PAM #define _PAM_FEATURE_ "+PAM" #else #define _PAM_FEATURE_ "-PAM" #endif #ifdef HAVE_AUDIT #define _AUDIT_FEATURE_ "+AUDIT" #else #define _AUDIT_FEATURE_ "-AUDIT" #endif #ifdef HAVE_SELINUX #define _SELINUX_FEATURE_ "+SELINUX" #else #define _SELINUX_FEATURE_ "-SELINUX" #endif #ifdef HAVE_APPARMOR #define _APPARMOR_FEATURE_ "+APPARMOR" #else #define _APPARMOR_FEATURE_ "-APPARMOR" #endif #ifdef HAVE_IMA #define _IMA_FEATURE_ "+IMA" #else #define _IMA_FEATURE_ "-IMA" #endif #ifdef HAVE_SMACK #define _SMACK_FEATURE_ "+SMACK" #else #define _SMACK_FEATURE_ "-SMACK" #endif #ifdef HAVE_SYSV_COMPAT #define _SYSVINIT_FEATURE_ "+SYSVINIT" #else #define _SYSVINIT_FEATURE_ "-SYSVINIT" #endif #ifdef HAVE_UTMP #define _UTMP_FEATURE_ "+UTMP" #else #define _UTMP_FEATURE_ "-UTMP" #endif #ifdef HAVE_LIBCRYPTSETUP #define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP" #else #define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" #endif #ifdef HAVE_GCRYPT #define _GCRYPT_FEATURE_ "+GCRYPT" #else #define _GCRYPT_FEATURE_ "-GCRYPT" #endif #ifdef HAVE_GNUTLS #define _GNUTLS_FEATURE_ "+GNUTLS" #else #define _GNUTLS_FEATURE_ "-GNUTLS" #endif #ifdef HAVE_ACL #define _ACL_FEATURE_ "+ACL" #else #define _ACL_FEATURE_ "-ACL" #endif #ifdef HAVE_XZ #define _XZ_FEATURE_ "+XZ" #else #define _XZ_FEATURE_ "-XZ" #endif #ifdef HAVE_LZ4 #define _LZ4_FEATURE_ "+LZ4" #else #define _LZ4_FEATURE_ "-LZ4" #endif #ifdef HAVE_SECCOMP #define _SECCOMP_FEATURE_ "+SECCOMP" #else #define _SECCOMP_FEATURE_ "-SECCOMP" #endif #ifdef HAVE_BLKID #define _BLKID_FEATURE_ "+BLKID" #else #define _BLKID_FEATURE_ "-BLKID" #endif #ifdef HAVE_ELFUTILS #define _ELFUTILS_FEATURE_ "+ELFUTILS" #else #define _ELFUTILS_FEATURE_ "-ELFUTILS" #endif #ifdef HAVE_KMOD #define _KMOD_FEATURE_ "+KMOD" #else #define _KMOD_FEATURE_ "-KMOD" #endif #ifdef HAVE_LIBIDN #define _IDN_FEATURE_ "+IDN" #else #define _IDN_FEATURE_ "-IDN" #endif #define SYSTEMD_FEATURES \ _PAM_FEATURE_ " " \ _AUDIT_FEATURE_ " " \ _SELINUX_FEATURE_ " " \ _IMA_FEATURE_ " " \ _APPARMOR_FEATURE_ " " \ _SMACK_FEATURE_ " " \ _SYSVINIT_FEATURE_ " " \ _UTMP_FEATURE_ " " \ _LIBCRYPTSETUP_FEATURE_ " " \ _GCRYPT_FEATURE_ " " \ _GNUTLS_FEATURE_ " " \ _ACL_FEATURE_ " " \ _XZ_FEATURE_ " " \ _LZ4_FEATURE_ " " \ _SECCOMP_FEATURE_ " " \ _BLKID_FEATURE_ " " \ _ELFUTILS_FEATURE_ " " \ _KMOD_FEATURE_ " " \ _IDN_FEATURE_ systemd-bootchart-233/src/cgroup-util.c000066400000000000000000000120751315600604400202470ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include "attributes.h" #include "cgroup-util.h" #include "def.h" #include "fd-util.h" #include "fileio.h" #include "macro.h" #include "missing.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" #define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) int cg_pid_get_path(const char *controller, pid_t pid, char **path) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; const char *fs; size_t cs = 0; int unified; assert(path); assert(pid >= 0); unified = cg_unified(); if (unified < 0) return unified; if (unified == 0) { if (controller) { if (!cg_controller_is_valid(controller)) return -EINVAL; } else controller = SYSTEMD_CGROUP_CONTROLLER; cs = strlen(controller); } fs = procfs_file_alloca(pid, "cgroup"); f = fopen(fs, "re"); if (!f) return errno == ENOENT ? -ESRCH : -errno; FOREACH_LINE(line, f, return -errno) { char *e, *p; truncate_nl(line); if (unified) { e = startswith(line, "0:"); if (!e) continue; e = strchr(e, ':'); if (!e) continue; } else { char *l; size_t k; const char *word, *state; bool found = false; l = strchr(line, ':'); if (!l) continue; l++; e = strchr(l, ':'); if (!e) continue; *e = 0; FOREACH_WORD_SEPARATOR(word, k, l, ",", state) { if (k == cs && memcmp(word, controller, cs) == 0) { found = true; break; } } if (!found) continue; } p = strdup(e + 1); if (!p) return -ENOMEM; *path = p; return 0; } return -ENODATA; } #define CONTROLLER_VALID \ DIGITS LETTERS \ "_" bool cg_controller_is_valid(const char *p) { const char *t, *s; if (!p) return false; s = startswith(p, "name="); if (s) p = s; if (*p == 0 || *p == '_') return false; for (t = p; *t; t++) if (!strchr(CONTROLLER_VALID, *t)) return false; if (t - p > FILENAME_MAX) return false; return true; } static thread_local int unified_cache = -1; int cg_unified(void) { struct statfs fs; /* Checks if we support the unified hierarchy. Returns an * error when the cgroup hierarchies aren't mounted yet or we * have any other trouble determining if the unified hierarchy * is supported. */ if (unified_cache >= 0) return unified_cache; if (statfs("/sys/fs/cgroup/", &fs) < 0) return -errno; if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC)) unified_cache = true; else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) unified_cache = false; else return -ENOMEDIUM; return unified_cache; } int cg_blkio_weight_parse(const char *s, uint64_t *ret) { uint64_t u; int r; if (isempty(s)) { *ret = CGROUP_BLKIO_WEIGHT_INVALID; return 0; } r = safe_atou64(s, &u); if (r < 0) return r; if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX) return -ERANGE; *ret = u; return 0; } systemd-bootchart-233/src/cgroup-util.h000066400000000000000000000054141315600604400202530ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include /* Special values for the cpu.shares attribute */ #define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) #define CGROUP_CPU_SHARES_MIN UINT64_C(2) #define CGROUP_CPU_SHARES_MAX UINT64_C(262144) #define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024) static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) { return x == CGROUP_CPU_SHARES_INVALID || (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX); } /* Special values for the blkio.weight attribute */ #define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1) #define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10) #define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000) #define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500) static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { return x == CGROUP_BLKIO_WEIGHT_INVALID || (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX); } /* * General rules: * * We accept named hierarchies in the syntax "foo" and "name=foo". * * We expect that named hierarchies do not conflict in name with a * kernel hierarchy, modulo the "name=" prefix. * * We always generate "normalized" controller names, i.e. without the * "name=" prefix. * * We require absolute cgroup paths. When returning, we will always * generate paths with multiple adjacent / removed. */ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self); int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool remove); int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem); int cg_pid_get_path(const char *controller, pid_t pid, char **path); int cg_pid_get_unit(pid_t pid, char **unit); int cg_pid_get_machine_name(pid_t pid, char **machine); bool cg_controller_is_valid(const char *p); int cg_slice_to_path(const char *unit, char **ret); int cg_unified(void); int cg_blkio_weight_parse(const char *s, uint64_t *ret); systemd-bootchart-233/src/conf-files.c000066400000000000000000000073471315600604400200300ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "conf-files.h" #include "dirent-util.h" #include "fd-util.h" #include "hash-funcs.h" #include "hashmap.h" #include "log.h" #include "macro.h" #include "path-util.h" #include "string-util.h" #include "strv.h" #include "util.h" static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { _cleanup_closedir_ DIR *dir = NULL; const char *dirpath; struct dirent *de; int r; assert(path); assert(suffix); dirpath = prefix_roota(root, path); dir = opendir(dirpath); if (!dir) { if (errno == ENOENT) return 0; return -errno; } FOREACH_DIRENT(de, dir, return -errno) { char *p; if (!dirent_is_file_with_suffix(de, suffix)) continue; p = strjoin(dirpath, "/", de->d_name, NULL); if (!p) return -ENOMEM; r = hashmap_put(h, basename(p), p); if (r == -EEXIST) { log_debug("Skipping overridden file: %s.", p); free(p); } else if (r < 0) { free(p); return r; } else if (r == 0) { log_debug("Duplicate file %s", p); free(p); } } return 0; } static int base_cmp(const void *a, const void *b) { const char *s1, *s2; s1 = *(char * const *)a; s2 = *(char * const *)b; return strcmp(basename(s1), basename(s2)); } static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) { _cleanup_hashmap_free_ Hashmap *fh = NULL; char **files, **p; int r; assert(strv); assert(suffix); /* This alters the dirs string array */ if (!path_strv_resolve_uniq(dirs, root)) return -ENOMEM; fh = hashmap_new(&string_hash_ops); if (!fh) return -ENOMEM; STRV_FOREACH(p, dirs) { r = files_add(fh, root, *p, suffix); if (r == -ENOMEM) return r; if (r < 0) log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p); } files = hashmap_get_strv(fh); if (!files) return -ENOMEM; qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); *strv = files; return 0; } int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) { _cleanup_strv_free_ char **dirs = NULL; assert(strv); assert(suffix); dirs = strv_split_nulstr(d); if (!dirs) return -ENOMEM; return conf_files_list_strv_internal(strv, suffix, root, dirs); } systemd-bootchart-233/src/conf-files.h000066400000000000000000000015451315600604400200270ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010-2012 Lennart Poettering Copyright 2010-2012 Kay Sievers systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, const char *dirs); systemd-bootchart-233/src/conf-parser.c000066400000000000000000000372441315600604400202210ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" #include "fd-util.h" #include "fs-util.h" #include "log.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" #include "strv.h" //#include "syslog-util.h" #include "utf8.h" int config_item_table_lookup( const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata) { const ConfigTableItem *t; assert(table); assert(lvalue); assert(func); assert(ltype); assert(data); for (t = table; t->lvalue; t++) { if (!streq(lvalue, t->lvalue)) continue; if (!streq_ptr(section, t->section)) continue; *func = t->parse; *ltype = t->ltype; *data = t->data; return 1; } return 0; } /* Run the user supplied parser for an assignment */ static int next_assignment(const char *unit, const char *filename, unsigned line, ConfigItemLookup lookup, const void *table, const char *section, unsigned section_line, const char *lvalue, const char *rvalue, bool relaxed, void *userdata) { ConfigParserCallback func = NULL; int ltype = 0; void *data = NULL; int r; assert(filename); assert(line > 0); assert(lookup); assert(lvalue); assert(rvalue); r = lookup(table, section, lvalue, &func, <ype, &data, userdata); if (r < 0) return r; if (r > 0) { if (func) return func(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata); return 0; } /* Warn about unknown non-extension fields. */ if (!relaxed && !startswith(lvalue, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section); return 0; } /* Parse a variable assignment line */ static int parse_line(const char* unit, const char *filename, unsigned line, const char *sections, ConfigItemLookup lookup, const void *table, bool relaxed, bool allow_include, char **section, unsigned *section_line, bool *section_ignored, char *l, void *userdata) { char *e; assert(filename); assert(line > 0); assert(lookup); assert(l); l = strstrip(l); if (!*l) return 0; if (strchr(COMMENTS "\n", *l)) return 0; if (startswith(l, ".include ")) { _cleanup_free_ char *fn = NULL; /* .includes are a bad idea, we only support them here * for historical reasons. They create cyclic include * problems and make it difficult to detect * configuration file changes with an easy * stat(). Better approaches, such as .d/ drop-in * snippets exist. * * Support for them should be eventually removed. */ if (!allow_include) { log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring."); return 0; } fn = file_in_same_dir(filename, strstrip(l+9)); if (!fn) return -ENOMEM; return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata); } if (*l == '[') { size_t k; char *n; k = strlen(l); assert(k > 0); if (l[k-1] != ']') { log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l); return -EBADMSG; } n = strndup(l+1, k-2); if (!n) return -ENOMEM; if (sections && !nulstr_contains(sections, n)) { if (!relaxed && !startswith(n, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n); free(n); *section = mfree(*section); *section_line = 0; *section_ignored = true; } else { free(*section); *section = n; *section_line = line; *section_ignored = false; } return 0; } if (sections && !*section) { if (!relaxed && !*section_ignored) log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring."); return 0; } e = strchr(l, '='); if (!e) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='."); return -EINVAL; } *e = 0; e++; return next_assignment(unit, filename, line, lookup, table, *section, *section_line, strstrip(l), strstrip(e), relaxed, userdata); } /* Go through the file and parse each line */ int config_parse(const char *unit, const char *filename, FILE *f, const char *sections, ConfigItemLookup lookup, const void *table, bool relaxed, bool allow_include, bool warn, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; bool section_ignored = false; int r; assert(filename); assert(lookup); if (!f) { f = ours = fopen(filename, "re"); if (!f) { /* Only log on request, except for ENOENT, * since we return 0 to the caller. */ if (warn || errno == ENOENT) log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, "Failed to open configuration file '%s': %m", filename); return errno == ENOENT ? 0 : -errno; } } fd_warn_permissions(filename, fileno(f)); while (!feof(f)) { char l[LINE_MAX], *p, *c = NULL, *e; bool escaped = false; if (!fgets(l, sizeof(l), f)) { if (feof(f)) break; log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); return -errno; } truncate_nl(l); if (continuation) { c = strappend(continuation, l); if (!c) { if (warn) log_oom(); return -ENOMEM; } continuation = mfree(continuation); p = c; } else p = l; for (e = p; *e; e++) { if (escaped) escaped = false; else if (*e == '\\') escaped = true; } if (escaped) { *(e-1) = ' '; if (c) continuation = c; else { continuation = strdup(l); if (!continuation) { if (warn) log_oom(); return -ENOMEM; } } continue; } r = parse_line(unit, filename, ++line, sections, lookup, table, relaxed, allow_include, §ion, §ion_line, §ion_ignored, p, userdata); free(c); if (r < 0) { if (warn) log_warning_errno(r, "Failed to parse file '%s': %m", filename); return r; } } return 0; } /* Parse each config file in the specified directories. */ int config_parse_many(const char *conf_file, const char *conf_file_dirs, const char *sections, ConfigItemLookup lookup, const void *table, bool relaxed, void *userdata) { _cleanup_strv_free_ char **files = NULL; char **fn; int r; r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); if (r < 0) return r; if (conf_file) { r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata); if (r < 0) return r; } STRV_FOREACH(fn, files) { r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata); if (r < 0) return r; } return 0; } #define DEFINE_PARSER(type, vartype, conv_func) \ int config_parse_##type( \ const char *unit, \ const char *filename, \ unsigned line, \ const char *section, \ unsigned section_line, \ const char *lvalue, \ int ltype, \ const char *rvalue, \ void *data, \ void *userdata) { \ \ vartype *i = data; \ int r; \ \ assert(filename); \ assert(lvalue); \ assert(rvalue); \ assert(data); \ \ r = conv_func(rvalue, i); \ if (r < 0) \ log_syntax(unit, LOG_ERR, filename, line, r, \ "Failed to parse %s value, ignoring: %s", \ #type, rvalue); \ \ return 0; \ } \ struct __useless_struct_to_allow_trailing_semicolon__ DEFINE_PARSER(int, int, safe_atoi); DEFINE_PARSER(double, double, safe_atod); int config_parse_bool(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { int k; bool *b = data; assert(filename); assert(lvalue); assert(rvalue); assert(data); k = parse_boolean(rvalue); if (k < 0) { log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue); return 0; } *b = !!k; return 0; } int config_parse_path( const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { char **s = data, *n; assert(filename); assert(lvalue); assert(rvalue); assert(data); if (!utf8_is_valid(rvalue)) { log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); return 0; } if (!path_is_absolute(rvalue)) { log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue); return 0; } n = strdup(rvalue); if (!n) return log_oom(); path_kill_slashes(n); free(*s); *s = n; return 0; } systemd-bootchart-233/src/conf-parser.h000066400000000000000000000307021315600604400202160ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "alloc-util.h" #include "log.h" #include "macro.h" /* An abstract parser for simple, line based, shallow configuration * files consisting of variable assignments only. */ /* Prototype for a parser for a specific configuration setting */ typedef int (*ConfigParserCallback)(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Wraps information for parsing a specific configuration variable, to * be stored in a simple array */ typedef struct ConfigTableItem { const char *section; /* Section */ const char *lvalue; /* Name of the variable */ ConfigParserCallback parse; /* Function that is called to parse the variable's value */ int ltype; /* Distinguish different variables passed to the same callback */ void *data; /* Where to store the variable's data */ } ConfigTableItem; /* Wraps information for parsing a specific configuration variable, to * be stored in a gperf perfect hashtable */ typedef struct ConfigPerfItem { const char *section_and_lvalue; /* Section + "." + name of the variable */ ConfigParserCallback parse; /* Function that is called to parse the variable's value */ int ltype; /* Distinguish different variables passed to the same callback */ size_t offset; /* Offset where to store data, from the beginning of userdata */ } ConfigPerfItem; /* Prototype for a low-level gperf lookup function */ typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length); /* Prototype for a generic high-level lookup function */ typedef int (*ConfigItemLookup)( const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); /* Linear table search implementation of ConfigItemLookup, based on * ConfigTableItem arrays */ int config_item_table_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); int config_parse(const char *unit, const char *filename, FILE *f, const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, bool relaxed, bool allow_include, bool warn, void *userdata); int config_parse_many(const char *conf_file, /* possibly NULL */ const char *conf_file_dirs, /* nulstr */ const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, bool relaxed, void *userdata); /* Generic parsers */ int config_parse_int(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_double(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bool(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_path(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ int function(const char *unit, \ const char *filename, \ unsigned line, \ const char *section, \ unsigned section_line, \ const char *lvalue, \ int ltype, \ const char *rvalue, \ void *data, \ void *userdata) { \ \ type *i = data, x; \ \ assert(filename); \ assert(lvalue); \ assert(rvalue); \ assert(data); \ \ if ((x = name##_from_string(rvalue)) < 0) { \ log_syntax(unit, LOG_ERR, filename, line, -x, \ msg ", ignoring: %s", rvalue); \ return 0; \ } \ \ *i = x; \ return 0; \ } #define DEFINE_CONFIG_PARSE_ENUMV(function,name,type,invalid,msg) \ int function(const char *unit, \ const char *filename, \ unsigned line, \ const char *section, \ unsigned section_line, \ const char *lvalue, \ int ltype, \ const char *rvalue, \ void *data, \ void *userdata) { \ \ type **enums = data, x, *ys; \ _cleanup_free_ type *xs = NULL; \ const char *word, *state; \ size_t l, i = 0; \ \ assert(filename); \ assert(lvalue); \ assert(rvalue); \ assert(data); \ \ xs = new0(type, 1); \ if(!xs) \ return -ENOMEM; \ \ *xs = invalid; \ \ FOREACH_WORD(word, l, rvalue, state) { \ _cleanup_free_ char *en = NULL; \ type *new_xs; \ \ en = strndup(word, l); \ if (!en) \ return -ENOMEM; \ \ if ((x = name##_from_string(en)) < 0) { \ log_syntax(unit, LOG_ERR, filename, line, \ -x, msg ", ignoring: %s", en); \ continue; \ } \ \ for (ys = xs; x != invalid && *ys != invalid; ys++) { \ if (*ys == x) { \ log_syntax(unit, LOG_ERR, filename, \ line, -x, \ "Duplicate entry, ignoring: %s", \ en); \ x = invalid; \ } \ } \ \ if (x == invalid) \ continue; \ \ *(xs + i) = x; \ new_xs = realloc(xs, (++i + 1) * sizeof(type)); \ if (new_xs) \ xs = new_xs; \ else \ return -ENOMEM; \ \ *(xs + i) = invalid; \ } \ \ free(*enums); \ *enums = xs; \ xs = NULL; \ \ return 0; \ } systemd-bootchart-233/src/def.h000066400000000000000000000056371315600604400165460ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include "util.h" #define DEFAULT_TIMEOUT_USEC (90*USEC_PER_SEC) #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) #define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC) #define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC) #define DEFAULT_START_LIMIT_BURST 5 /* The default time after which exit-on-idle services exit. This * should be kept lower than the watchdog timeout, because otherwise * the watchdog pings will keep the loop busy. */ #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) /* The default value for the net.unix.max_dgram_qlen sysctl */ #define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT #define SIGNALS_IGNORE SIGPIPE #define REBOOT_PARAM_FILE "/run/systemd/reboot-param" #ifdef HAVE_SPLIT_USR #define KBD_KEYMAP_DIRS \ "/usr/share/keymaps/\0" \ "/usr/share/kbd/keymaps/\0" \ "/usr/lib/kbd/keymaps/\0" \ "/lib/kbd/keymaps/\0" #else #define KBD_KEYMAP_DIRS \ "/usr/share/keymaps/\0" \ "/usr/share/kbd/keymaps/\0" \ "/usr/lib/kbd/keymaps/\0" #endif #define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" #define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus" #define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS #define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus" #define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus" #ifndef TTY_GID #define TTY_GID 5 #endif #define NOTIFY_FD_MAX 768 #define NOTIFY_BUFFER_MAX PIPE_BUF #ifdef HAVE_SPLIT_USR #define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0" #else #define _CONF_PATHS_SPLIT_USR(n) #endif /* Return a nulstr for a standard cascade of configuration paths, * suitable to pass to conf_files_list_nulstr() or config_parse_many() * to implement drop-in directories for extending configuration * files. */ #define CONF_PATHS_NULSTR(n) \ "/etc/" n "\0" \ "/run/" n "\0" \ "/usr/local/lib/" n "\0" \ "/usr/lib/" n "\0" \ _CONF_PATHS_SPLIT_USR(n) systemd-bootchart-233/src/dirent-util.c000066400000000000000000000020721315600604400202310ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010-2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include "dirent-util.h" #include "macro.h" #include "string-util.h" bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { assert(de); if (de->d_type != DT_REG && de->d_type != DT_LNK && de->d_type != DT_UNKNOWN) return false; return endswith(de->d_name, suffix); } systemd-bootchart-233/src/dirent-util.h000066400000000000000000000026461315600604400202450ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; #define FOREACH_DIRENT(de, d, on_error) \ for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ if (!de) { \ if (errno > 0) { \ on_error; \ } \ break; \ } else systemd-bootchart-233/src/fd-util.c000066400000000000000000000053331315600604400173400ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include "fd-util.h" #include "macro.h" #include "util.h" int close_nointr(int fd) { assert(fd >= 0); if (close(fd) >= 0) return 0; /* * Just ignore EINTR; a retry loop is the wrong thing to do on * Linux. * * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html * https://bugzilla.gnome.org/show_bug.cgi?id=682819 * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain */ if (errno == EINTR) return 0; return -errno; } int safe_close(int fd) { /* * Like close_nointr() but cannot fail. Guarantees errno is * unchanged. Is a NOP with negative fds passed, and returns * -1, so that it can be used in this syntax: * * fd = safe_close(fd); */ if (fd >= 0) { PROTECT_ERRNO; /* The kernel might return pretty much any error code * via close(), but the fd will be closed anyway. The * only condition we want to check for here is whether * the fd was invalid at all... */ assert_se(close_nointr(fd) != -EBADF); } return -1; } int fclose_nointr(FILE *f) { assert(f); /* Same as close_nointr(), but for fclose() */ if (fclose(f) == 0) return 0; if (errno == EINTR) return 0; return -errno; } FILE* safe_fclose(FILE *f) { /* Same as safe_close(), but for fclose() */ if (f) { PROTECT_ERRNO; assert_se(fclose_nointr(f) != EBADF); } return NULL; } DIR* safe_closedir(DIR *d) { if (d) { PROTECT_ERRNO; assert_se(closedir(d) >= 0 || errno != EBADF); } return NULL; } systemd-bootchart-233/src/fd-util.h000066400000000000000000000033011315600604400173360ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" #include "macro.h" /* Make sure we can distinguish fd 0 and NULL */ #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) #define PTR_TO_FD(p) (PTR_TO_INT(p)-1) int close_nointr(int fd); int safe_close(int fd); int fclose_nointr(FILE *f); FILE* safe_fclose(FILE *f); DIR* safe_closedir(DIR *f); static inline void closep(int *fd) { safe_close(*fd); } static inline void fclosep(FILE **f) { safe_fclose(*f); } DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); #define _cleanup_close_ _cleanup_(closep) #define _cleanup_fclose_ _cleanup_(fclosep) #define _cleanup_pclose_ _cleanup_(pclosep) #define _cleanup_closedir_ _cleanup_(closedirp) /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) systemd-bootchart-233/src/fileio.c000066400000000000000000000427511315600604400172500ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include #include "alloc-util.h" #include "ctype.h" #include "fd-util.h" #include "fileio.h" #include "log.h" #include "macro.h" #include "string-util.h" #include "utf8.h" int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; char t[LINE_MAX], *c; assert(fn); assert(line); f = fopen(fn, "re"); if (!f) return -errno; if (!fgets(t, sizeof(t), f)) { if (ferror(f)) return errno > 0 ? -errno : -EIO; t[0] = 0; } c = strdup(t); if (!c) return -ENOMEM; truncate_nl(c); *line = c; return 0; } int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; struct stat st; assert(f); assert(contents); if (fstat(fileno(f), &st) < 0) return -errno; n = LINE_MAX; if (S_ISREG(st.st_mode)) { /* Safety check */ if (st.st_size > 4*1024*1024) return -E2BIG; /* Start with the right file size, but be prepared for * files from /proc which generally report a file size * of 0 */ if (st.st_size > 0) n = st.st_size; } l = 0; for (;;) { char *t; size_t k; t = realloc(buf, n+1); if (!t) return -ENOMEM; buf = t; k = fread(buf + l, 1, n - l, f); if (k <= 0) { if (ferror(f)) return -errno; break; } l += k; n *= 2; /* Safety check */ if (n > 4*1024*1024) return -E2BIG; } buf[l] = 0; *contents = buf; buf = NULL; /* do not free */ if (size) *size = l; return 0; } int read_full_file(const char *fn, char **contents, size_t *size) { _cleanup_fclose_ FILE *f = NULL; assert(fn); assert(contents); f = fopen(fn, "re"); if (!f) return -errno; return read_full_stream(f, contents, size); } static int parse_env_file_internal( FILE *f, const char *fname, const char *newline, int (*push) (const char *filename, unsigned line, const char *key, char *value, void *userdata, int *n_pushed), void *userdata, int *n_pushed) { _cleanup_free_ char *contents = NULL, *key = NULL; size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; char *p, *value = NULL; int r; unsigned line = 1; enum { PRE_KEY, KEY, PRE_VALUE, VALUE, VALUE_ESCAPE, SINGLE_QUOTE_VALUE, SINGLE_QUOTE_VALUE_ESCAPE, DOUBLE_QUOTE_VALUE, DOUBLE_QUOTE_VALUE_ESCAPE, COMMENT, COMMENT_ESCAPE } state = PRE_KEY; assert(newline); if (f) r = read_full_stream(f, &contents, NULL); else r = read_full_file(fname, &contents, NULL); if (r < 0) return r; for (p = contents; *p; p++) { char c = *p; switch (state) { case PRE_KEY: if (strchr(COMMENTS, c)) state = COMMENT; else if (!strchr(WHITESPACE, c)) { state = KEY; last_key_whitespace = (size_t) -1; if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { r = -ENOMEM; goto fail; } key[n_key++] = c; } break; case KEY: if (strchr(newline, c)) { state = PRE_KEY; line ++; n_key = 0; } else if (c == '=') { state = PRE_VALUE; last_value_whitespace = (size_t) -1; } else { if (!strchr(WHITESPACE, c)) last_key_whitespace = (size_t) -1; else if (last_key_whitespace == (size_t) -1) last_key_whitespace = n_key; if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { r = -ENOMEM; goto fail; } key[n_key++] = c; } break; case PRE_VALUE: if (strchr(newline, c)) { state = PRE_KEY; line ++; key[n_key] = 0; if (value) value[n_value] = 0; /* strip trailing whitespace from key */ if (last_key_whitespace != (size_t) -1) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) goto fail; n_key = 0; value = NULL; value_alloc = n_value = 0; } else if (c == '\'') state = SINGLE_QUOTE_VALUE; else if (c == '\"') state = DOUBLE_QUOTE_VALUE; else if (c == '\\') state = VALUE_ESCAPE; else if (!strchr(WHITESPACE, c)) { state = VALUE; if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case VALUE: if (strchr(newline, c)) { state = PRE_KEY; line ++; key[n_key] = 0; if (value) value[n_value] = 0; /* Chomp off trailing whitespace from value */ if (last_value_whitespace != (size_t) -1) value[last_value_whitespace] = 0; /* strip trailing whitespace from key */ if (last_key_whitespace != (size_t) -1) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) goto fail; n_key = 0; value = NULL; value_alloc = n_value = 0; } else if (c == '\\') { state = VALUE_ESCAPE; last_value_whitespace = (size_t) -1; } else { if (!strchr(WHITESPACE, c)) last_value_whitespace = (size_t) -1; else if (last_value_whitespace == (size_t) -1) last_value_whitespace = n_value; if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case VALUE_ESCAPE: state = VALUE; if (!strchr(newline, c)) { /* Escaped newlines we eat up entirely */ if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case SINGLE_QUOTE_VALUE: if (c == '\'') state = PRE_VALUE; else if (c == '\\') state = SINGLE_QUOTE_VALUE_ESCAPE; else { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case SINGLE_QUOTE_VALUE_ESCAPE: state = SINGLE_QUOTE_VALUE; if (!strchr(newline, c)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case DOUBLE_QUOTE_VALUE: if (c == '\"') state = PRE_VALUE; else if (c == '\\') state = DOUBLE_QUOTE_VALUE_ESCAPE; else { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case DOUBLE_QUOTE_VALUE_ESCAPE: state = DOUBLE_QUOTE_VALUE; if (!strchr(newline, c)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case COMMENT: if (c == '\\') state = COMMENT_ESCAPE; else if (strchr(newline, c)) { state = PRE_KEY; line ++; } break; case COMMENT_ESCAPE: state = COMMENT; break; } } if (state == PRE_VALUE || state == VALUE || state == VALUE_ESCAPE || state == SINGLE_QUOTE_VALUE || state == SINGLE_QUOTE_VALUE_ESCAPE || state == DOUBLE_QUOTE_VALUE || state == DOUBLE_QUOTE_VALUE_ESCAPE) { key[n_key] = 0; if (value) value[n_value] = 0; if (state == VALUE) if (last_value_whitespace != (size_t) -1) value[last_value_whitespace] = 0; /* strip trailing whitespace from key */ if (last_key_whitespace != (size_t) -1) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) goto fail; } return 0; fail: free(value); return r; } static int parse_env_file_push( const char *filename, unsigned line, const char *key, char *value, void *userdata, int *n_pushed) { const char *k; va_list aq, *ap = userdata; if (!utf8_is_valid(key)) { _cleanup_free_ char *p; p = utf8_escape_invalid(key); log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); return -EINVAL; } if (value && !utf8_is_valid(value)) { _cleanup_free_ char *p; p = utf8_escape_invalid(value); log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); return -EINVAL; } va_copy(aq, *ap); while ((k = va_arg(aq, const char *))) { char **v; v = va_arg(aq, char **); if (streq(key, k)) { va_end(aq); free(*v); *v = value; if (n_pushed) (*n_pushed)++; return 1; } } va_end(aq); free(value); return 0; } int parse_env_file( const char *fname, const char *newline, ...) { va_list ap; int r, n_pushed = 0; if (!newline) newline = NEWLINE; va_start(ap, newline); r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed); va_end(ap); return r < 0 ? r : n_pushed; } /** * Retrieve one field from a file like /proc/self/status. pattern * should not include whitespace or the delimiter (':'). pattern matches only * the beginning of a line. Whitespace before ':' is skipped. Whitespace and * zeros after the ':' will be skipped. field must be freed afterwards. * terminator specifies the terminating characters of the field value (not * included in the value). */ int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { _cleanup_free_ char *status = NULL; char *t, *f; size_t len; int r; assert(terminator); assert(filename); assert(pattern); assert(field); r = read_full_file(filename, &status, NULL); if (r < 0) return r; t = status; do { bool pattern_ok; do { t = strstr(t, pattern); if (!t) return -ENOENT; /* Check that pattern occurs in beginning of line. */ pattern_ok = (t == status || t[-1] == '\n'); t += strlen(pattern); } while (!pattern_ok); t += strspn(t, " \t"); if (!*t) return -ENOENT; } while (*t != ':'); t++; if (*t) { t += strspn(t, " \t"); /* Also skip zeros, because when this is used for * capabilities, we don't want the zeros. This way the * same capability set always maps to the same string, * irrespective of the total capability set size. For * other numbers it shouldn't matter. */ t += strspn(t, "0"); /* Back off one char if there's nothing but whitespace and zeros */ if (!*t || isspace(*t)) t --; } len = strcspn(t, terminator); f = strndup(t, len); if (!f) return -ENOMEM; *field = f; return 0; } systemd-bootchart-233/src/fileio.h000066400000000000000000000035011315600604400172430ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include "attributes.h" typedef enum { WRITE_STRING_FILE_CREATE = 1, WRITE_STRING_FILE_ATOMIC = 2, WRITE_STRING_FILE_AVOID_NEWLINE = 4, WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8, } WriteStringFileFlags; int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); #define FOREACH_LINE(line, f, on_error) \ for (;;) \ if (!fgets(line, sizeof(line), f)) { \ if (ferror(f)) { \ on_error; \ } \ break; \ } else systemd-bootchart-233/src/formats-util.h000066400000000000000000000027401315600604400204260ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2015 Ronny Chevalier systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #if SIZEOF_PID_T == 4 # define PID_PRI PRIi32 #elif SIZEOF_PID_T == 2 # define PID_PRI PRIi16 #else # error Unknown pid_t size #endif #define PID_FMT "%" PID_PRI #if SIZEOF_UID_T == 4 # define UID_FMT "%" PRIu32 #elif SIZEOF_UID_T == 2 # define UID_FMT "%" PRIu16 #else # error Unknown uid_t size #endif #if SIZEOF_GID_T == 4 # define GID_FMT "%" PRIu32 #elif SIZEOF_GID_T == 2 # define GID_FMT "%" PRIu16 #else # error Unknown gid_t size #endif #if SIZEOF_TIME_T == 8 # define PRI_TIME PRIi64 #elif SIZEOF_TIME_T == 4 # define PRI_TIME PRIu32 #else # error Unknown time_t size #endif #if SIZEOF_RLIM_T == 8 # define RLIM_FMT "%" PRIu64 #elif SIZEOF_RLIM_T == 4 # define RLIM_FMT "%" PRIu32 #else # error Unknown rlim_t size #endif systemd-bootchart-233/src/fs-util.c000066400000000000000000000030741315600604400173570ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "fs-util.h" #include "log.h" int fd_warn_permissions(const char *path, int fd) { struct stat st; if (fstat(fd, &st) < 0) return -errno; if (st.st_mode & 0111) log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); if (st.st_mode & 0002) log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); if (getpid() == 1 && (st.st_mode & 0044) != 0044) log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); return 0; } systemd-bootchart-233/src/fs-util.h000066400000000000000000000026051315600604400173630ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include int fd_warn_permissions(const char *path, int fd); #define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) #define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ for ((e) = &buffer.ev; \ (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) union inotify_event_buffer { struct inotify_event ev; uint8_t raw[INOTIFY_EVENT_MAX]; }; systemd-bootchart-233/src/hash-funcs.c000066400000000000000000000045011315600604400200270ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering Copyright 2014 Michal Schmidt systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include "hash-funcs.h" void string_hash_func(const void *p, struct siphash *state) { siphash24_compress(p, strlen(p) + 1, state); } int string_compare_func(const void *a, const void *b) { return strcmp(a, b); } const struct hash_ops string_hash_ops = { .hash = string_hash_func, .compare = string_compare_func }; void trivial_hash_func(const void *p, struct siphash *state) { siphash24_compress(&p, sizeof(p), state); } int trivial_compare_func(const void *a, const void *b) { return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops trivial_hash_ops = { .hash = trivial_hash_func, .compare = trivial_compare_func }; void uint64_hash_func(const void *p, struct siphash *state) { siphash24_compress(p, sizeof(uint64_t), state); } int uint64_compare_func(const void *_a, const void *_b) { uint64_t a, b; a = *(const uint64_t*) _a; b = *(const uint64_t*) _b; return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops uint64_hash_ops = { .hash = uint64_hash_func, .compare = uint64_compare_func }; #if SIZEOF_DEV_T != 8 void devt_hash_func(const void *p, struct siphash *state) { siphash24_compress(p, sizeof(dev_t), state); } int devt_compare_func(const void *_a, const void *_b) { dev_t a, b; a = *(const dev_t*) _a; b = *(const dev_t*) _b; return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops devt_hash_ops = { .hash = devt_hash_func, .compare = devt_compare_func }; #endif systemd-bootchart-233/src/hash-funcs.h000066400000000000000000000045471315600604400200460ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering Copyright 2014 Michal Schmidt systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include "attributes.h" #include "siphash24.h" typedef void (*hash_func_t)(const void *p, struct siphash *state); typedef int (*compare_func_t)(const void *a, const void *b); struct hash_ops { hash_func_t hash; compare_func_t compare; }; void string_hash_func(const void *p, struct siphash *state); int string_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops string_hash_ops; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ void trivial_hash_func(const void *p, struct siphash *state); int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; /* 32bit values we can always just embed in the pointer itself, but * in order to support 32bit archs we need store 64bit values * indirectly, since they don't fit in a pointer. */ void uint64_hash_func(const void *p, struct siphash *state); int uint64_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops uint64_hash_ops; /* On some archs dev_t is 32bit, and on others 64bit. And sometimes * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 void devt_hash_func(const void *p, struct siphash *state) _pure_; int devt_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops devt_hash_ops = { .hash = devt_hash_func, .compare = devt_compare_func }; #else #define devt_hash_func uint64_hash_func #define devt_compare_func uint64_compare_func #define devt_hash_ops uint64_hash_ops #endif systemd-bootchart-233/src/hashmap.c000066400000000000000000001557561315600604400174340ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering Copyright 2014 Michal Schmidt systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include "alloc-util.h" #include "hashmap.h" #include "macro.h" #include "mempool.h" #include "process-util.h" #include "random-util.h" #include "set.h" #include "siphash24.h" #include "strv.h" #include "util.h" #ifdef ENABLE_DEBUG_HASHMAP #include #include "list.h" #endif /* * Implementation of hashmaps. * Addressing: open * - uses less RAM compared to closed addressing (chaining), because * our entries are small (especially in Sets, which tend to contain * the majority of entries in systemd). * Collision resolution: Robin Hood * - tends to equalize displacement of entries from their optimal buckets. * Probe sequence: linear * - though theoretically worse than random probing/uniform hashing/double * hashing, it is good for cache locality. * * References: * Celis, P. 1986. Robin Hood Hashing. * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada. * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf * - The results are derived for random probing. Suggests deletion with * tombstones and two mean-centered search methods. None of that works * well for linear probing. * * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies. * ACM Trans. Algorithms 1, 2 (October 2005), 177-213. * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964 * http://www.math.uu.se/~svante/papers/sj157.pdf * - Applies to Robin Hood with linear probing. Contains remarks on * the unsuitability of mean-centered search with linear probing. * * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing. * ACM Trans. Algorithms 1, 2 (October 2005), 214-242. * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965 * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes * in a successful search), and Janson writes about displacement. C = d + 1. * * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion. * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/ * - Explanation of backward shift deletion with pictures. * * Khuong, P. 2013. The Other Robin Hood Hashing. * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/ * - Short summary of random vs. linear probing, and tombstones vs. backward shift. */ /* * XXX Ideas for improvement: * For unordered hashmaps, randomize iteration order, similarly to Perl: * http://blog.booking.com/hardening-perls-hash-function.html */ /* INV_KEEP_FREE = 1 / (1 - max_load_factor) * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */ #define INV_KEEP_FREE 5U /* Fields common to entries of all hashmap/set types */ struct hashmap_base_entry { const void *key; }; /* Entry types for specific hashmap/set types * hashmap_base_entry must be at the beginning of each entry struct. */ struct plain_hashmap_entry { struct hashmap_base_entry b; void *value; }; struct ordered_hashmap_entry { struct plain_hashmap_entry p; unsigned iterate_next, iterate_previous; }; struct set_entry { struct hashmap_base_entry b; }; /* In several functions it is advantageous to have the hash table extended * virtually by a couple of additional buckets. We reserve special index values * for these "swap" buckets. */ #define _IDX_SWAP_BEGIN (UINT_MAX - 3) #define IDX_PUT (_IDX_SWAP_BEGIN + 0) #define IDX_TMP (_IDX_SWAP_BEGIN + 1) #define _IDX_SWAP_END (_IDX_SWAP_BEGIN + 2) #define IDX_FIRST (UINT_MAX - 1) /* special index for freshly initialized iterators */ #define IDX_NIL UINT_MAX /* special index value meaning "none" or "end" */ assert_cc(IDX_FIRST == _IDX_SWAP_END); assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST); /* Storage space for the "swap" buckets. * All entry types can fit into a ordered_hashmap_entry. */ struct swap_entries { struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN]; }; /* Distance from Initial Bucket */ typedef uint8_t dib_raw_t; #define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */ #define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */ #define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */ #define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */ #define DIB_FREE UINT_MAX #ifdef ENABLE_DEBUG_HASHMAP struct hashmap_debug_info { LIST_FIELDS(struct hashmap_debug_info, debug_list); unsigned max_entries; /* high watermark of n_entries */ /* who allocated this hashmap */ int line; const char *file; const char *func; /* fields to detect modification while iterating */ unsigned put_count; /* counts puts into the hashmap */ unsigned rem_count; /* counts removals from hashmap */ unsigned last_rem_idx; /* remembers last removal index */ }; /* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */ static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list); static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER; #define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug; #else /* !ENABLE_DEBUG_HASHMAP */ #define HASHMAP_DEBUG_FIELDS #endif /* ENABLE_DEBUG_HASHMAP */ enum HashmapType { HASHMAP_TYPE_PLAIN, HASHMAP_TYPE_ORDERED, HASHMAP_TYPE_SET, _HASHMAP_TYPE_MAX }; struct _packed_ indirect_storage { char *storage; /* where buckets and DIBs are stored */ uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ unsigned n_entries; /* number of stored entries */ unsigned n_buckets; /* number of buckets */ unsigned idx_lowest_entry; /* Index below which all buckets are free. Makes "while(hashmap_steal_first())" loops O(n) instead of O(n^2) for unordered hashmaps. */ uint8_t _pad[3]; /* padding for the whole HashmapBase */ /* The bitfields in HashmapBase complete the alignment of the whole thing. */ }; struct direct_storage { /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ char storage[sizeof(struct indirect_storage)]; }; #define DIRECT_BUCKETS(entry_t) \ (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t))) /* We should be able to store at least one entry directly. */ assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1); /* We have 3 bits for n_direct_entries. */ assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3)); /* Hashmaps with directly stored entries all use this shared hash key. * It's no big deal if the key is guessed, because there can be only * a handful of directly stored entries in a hashmap. When a hashmap * outgrows direct storage, it gets its own key for indirect storage. */ static uint8_t shared_hash_key[HASH_KEY_SIZE]; static bool shared_hash_key_initialized; /* Fields that all hashmap/set types must have */ struct HashmapBase { const struct hash_ops *hash_ops; /* hash and compare ops to use */ union _packed_ { struct indirect_storage indirect; /* if has_indirect */ struct direct_storage direct; /* if !has_indirect */ }; enum HashmapType type:2; /* HASHMAP_TYPE_* */ bool has_indirect:1; /* whether indirect storage is used */ unsigned n_direct_entries:3; /* Number of entries in direct storage. * Only valid if !has_indirect. */ bool from_pool:1; /* whether was allocated from mempool */ HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ }; /* Specific hash types * HashmapBase must be at the beginning of each hashmap struct. */ struct Hashmap { struct HashmapBase b; }; struct OrderedHashmap { struct HashmapBase b; unsigned iterate_list_head, iterate_list_tail; }; struct Set { struct HashmapBase b; }; DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8); DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8); /* No need for a separate Set pool */ assert_cc(sizeof(Hashmap) == sizeof(Set)); struct hashmap_type_info { size_t head_size; size_t entry_size; struct mempool *mempool; unsigned n_direct_buckets; }; static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { [HASHMAP_TYPE_PLAIN] = { .head_size = sizeof(Hashmap), .entry_size = sizeof(struct plain_hashmap_entry), .mempool = &hashmap_pool, .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry), }, [HASHMAP_TYPE_ORDERED] = { .head_size = sizeof(OrderedHashmap), .entry_size = sizeof(struct ordered_hashmap_entry), .mempool = &ordered_hashmap_pool, .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry), }, [HASHMAP_TYPE_SET] = { .head_size = sizeof(Set), .entry_size = sizeof(struct set_entry), .mempool = &hashmap_pool, .n_direct_buckets = DIRECT_BUCKETS(struct set_entry), }, }; static unsigned n_buckets(HashmapBase *h) { return h->has_indirect ? h->indirect.n_buckets : hashmap_type_info[h->type].n_direct_buckets; } static unsigned n_entries(HashmapBase *h) { return h->has_indirect ? h->indirect.n_entries : h->n_direct_entries; } static void n_entries_inc(HashmapBase *h) { if (h->has_indirect) h->indirect.n_entries++; else h->n_direct_entries++; } static void n_entries_dec(HashmapBase *h) { if (h->has_indirect) h->indirect.n_entries--; else h->n_direct_entries--; } static char *storage_ptr(HashmapBase *h) { return h->has_indirect ? h->indirect.storage : h->direct.storage; } static uint8_t *hash_key(HashmapBase *h) { return h->has_indirect ? h->indirect.hash_key : shared_hash_key; } static unsigned base_bucket_hash(HashmapBase *h, const void *p) { struct siphash state; uint64_t hash; siphash24_init(&state, hash_key(h)); h->hash_ops->hash(p, &state); hash = siphash24_finalize(&state); return (unsigned) (hash % n_buckets(h)); } #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { static uint8_t current[HASH_KEY_SIZE]; static bool current_initialized = false; /* Returns a hash function key to use. In order to keep things * fast we will not generate a new key each time we allocate a * new hash table. Instead, we'll just reuse the most recently * generated one, except if we never generated one or when we * are rehashing an entire hash table because we reached a * fill level */ if (!current_initialized || !reuse_is_ok) { random_bytes(current, sizeof(current)); current_initialized = true; } memcpy(hash_key, current, sizeof(current)); } static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { return (struct hashmap_base_entry*) (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); } static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); } static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) { return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); } static struct set_entry *set_bucket_at(Set *h, unsigned idx) { return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx); } static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) { return &swap->e[idx - _IDX_SWAP_BEGIN]; } /* Returns a pointer to the bucket at index idx. * Understands real indexes and swap indexes, hence "_virtual". */ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap, unsigned idx) { if (idx < _IDX_SWAP_BEGIN) return bucket_at(h, idx); if (idx < _IDX_SWAP_END) return &bucket_at_swap(swap, idx)->p.b; assert_not_reached("Invalid index"); } static dib_raw_t *dib_raw_ptr(HashmapBase *h) { return (dib_raw_t*) (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); } static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) { return idx >= from ? idx - from : n_buckets(h) + idx - from; } static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) { unsigned initial_bucket; if (raw_dib == DIB_RAW_FREE) return DIB_FREE; if (_likely_(raw_dib < DIB_RAW_OVERFLOW)) return raw_dib; /* * Having an overflow DIB value is very unlikely. The hash function * would have to be bad. For example, in a table of size 2^24 filled * to load factor 0.9 the maximum observed DIB is only about 60. * In theory (assuming I used Maxima correctly), for an infinite size * hash table with load factor 0.8 the probability of a given entry * having DIB > 40 is 1.9e-8. * This returns the correct DIB value by recomputing the hash value in * the unlikely case. XXX Hitting this case could be a hint to rehash. */ initial_bucket = bucket_hash(h, bucket_at(h, idx)->key); return bucket_distance(h, idx, initial_bucket); } static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) { dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE; } static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) { dib_raw_t *dibs; dibs = dib_raw_ptr(h); for ( ; idx < n_buckets(h); idx++) if (dibs[idx] != DIB_RAW_FREE) return idx; return IDX_NIL; } static void bucket_mark_free(HashmapBase *h, unsigned idx) { memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size); bucket_set_dib(h, idx, DIB_FREE); } static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap, unsigned from, unsigned to) { struct hashmap_base_entry *e_from, *e_to; assert(from != to); e_from = bucket_at_virtual(h, swap, from); e_to = bucket_at_virtual(h, swap, to); memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size); if (h->type == HASHMAP_TYPE_ORDERED) { OrderedHashmap *lh = (OrderedHashmap*) h; struct ordered_hashmap_entry *le, *le_to; le_to = (struct ordered_hashmap_entry*) e_to; if (le_to->iterate_next != IDX_NIL) { le = (struct ordered_hashmap_entry*) bucket_at_virtual(h, swap, le_to->iterate_next); le->iterate_previous = to; } if (le_to->iterate_previous != IDX_NIL) { le = (struct ordered_hashmap_entry*) bucket_at_virtual(h, swap, le_to->iterate_previous); le->iterate_next = to; } if (lh->iterate_list_head == from) lh->iterate_list_head = to; if (lh->iterate_list_tail == from) lh->iterate_list_tail = to; } } static unsigned next_idx(HashmapBase *h, unsigned idx) { return (idx + 1U) % n_buckets(h); } static unsigned prev_idx(HashmapBase *h, unsigned idx) { return (n_buckets(h) + idx - 1U) % n_buckets(h); } static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) { switch (h->type) { case HASHMAP_TYPE_PLAIN: case HASHMAP_TYPE_ORDERED: return ((struct plain_hashmap_entry*)e)->value; case HASHMAP_TYPE_SET: return (void*) e->key; default: assert_not_reached("Unknown hashmap type"); } } static void base_remove_entry(HashmapBase *h, unsigned idx) { unsigned left, right, prev, dib; dib_raw_t raw_dib, *dibs; dibs = dib_raw_ptr(h); assert(dibs[idx] != DIB_RAW_FREE); #ifdef ENABLE_DEBUG_HASHMAP h->debug.rem_count++; h->debug.last_rem_idx = idx; #endif left = idx; /* Find the stop bucket ("right"). It is either free or has DIB == 0. */ for (right = next_idx(h, left); ; right = next_idx(h, right)) { raw_dib = dibs[right]; if (raw_dib == 0 || raw_dib == DIB_RAW_FREE) break; /* The buckets are not supposed to be all occupied and with DIB > 0. * That would mean we could make everyone better off by shifting them * backward. This scenario is impossible. */ assert(left != right); } if (h->type == HASHMAP_TYPE_ORDERED) { OrderedHashmap *lh = (OrderedHashmap*) h; struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx); if (le->iterate_next != IDX_NIL) ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous; else lh->iterate_list_tail = le->iterate_previous; if (le->iterate_previous != IDX_NIL) ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next; else lh->iterate_list_head = le->iterate_next; } /* Now shift all buckets in the interval (left, right) one step backwards */ for (prev = left, left = next_idx(h, left); left != right; prev = left, left = next_idx(h, left)) { dib = bucket_calculate_dib(h, left, dibs[left]); assert(dib != 0); bucket_move_entry(h, NULL, left, prev); bucket_set_dib(h, prev, dib - 1); } bucket_mark_free(h, prev); n_entries_dec(h); } #define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx) static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) { struct ordered_hashmap_entry *e; unsigned idx; assert(h); assert(i); if (i->idx == IDX_NIL) goto at_end; if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL) goto at_end; if (i->idx == IDX_FIRST) { idx = h->iterate_list_head; e = ordered_bucket_at(h, idx); } else { idx = i->idx; e = ordered_bucket_at(h, idx); /* * We allow removing the current entry while iterating, but removal may cause * a backward shift. The next entry may thus move one bucket to the left. * To detect when it happens, we remember the key pointer of the entry we were * going to iterate next. If it does not match, there was a backward shift. */ if (e->p.b.key != i->next_key) { idx = prev_idx(HASHMAP_BASE(h), idx); e = ordered_bucket_at(h, idx); } assert(e->p.b.key == i->next_key); } #ifdef ENABLE_DEBUG_HASHMAP i->prev_idx = idx; #endif if (e->iterate_next != IDX_NIL) { struct ordered_hashmap_entry *n; i->idx = e->iterate_next; n = ordered_bucket_at(h, i->idx); i->next_key = n->p.b.key; } else i->idx = IDX_NIL; return idx; at_end: i->idx = IDX_NIL; return IDX_NIL; } static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) { unsigned idx; assert(h); assert(i); if (i->idx == IDX_NIL) goto at_end; if (i->idx == IDX_FIRST) { /* fast forward to the first occupied bucket */ if (h->has_indirect) { i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry); h->indirect.idx_lowest_entry = i->idx; } else i->idx = skip_free_buckets(h, 0); if (i->idx == IDX_NIL) goto at_end; } else { struct hashmap_base_entry *e; assert(i->idx > 0); e = bucket_at(h, i->idx); /* * We allow removing the current entry while iterating, but removal may cause * a backward shift. The next entry may thus move one bucket to the left. * To detect when it happens, we remember the key pointer of the entry we were * going to iterate next. If it does not match, there was a backward shift. */ if (e->key != i->next_key) e = bucket_at(h, --i->idx); assert(e->key == i->next_key); } idx = i->idx; #ifdef ENABLE_DEBUG_HASHMAP i->prev_idx = idx; #endif i->idx = skip_free_buckets(h, i->idx + 1); if (i->idx != IDX_NIL) i->next_key = bucket_at(h, i->idx)->key; else i->idx = IDX_NIL; return idx; at_end: i->idx = IDX_NIL; return IDX_NIL; } static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) { if (!h) { i->idx = IDX_NIL; return IDX_NIL; } #ifdef ENABLE_DEBUG_HASHMAP if (i->idx == IDX_FIRST) { i->put_count = h->debug.put_count; i->rem_count = h->debug.rem_count; } else { /* While iterating, must not add any new entries */ assert(i->put_count == h->debug.put_count); /* ... or remove entries other than the current one */ assert(i->rem_count == h->debug.rem_count || (i->rem_count == h->debug.rem_count - 1 && i->prev_idx == h->debug.last_rem_idx)); /* Reset our removals counter */ i->rem_count = h->debug.rem_count; } #endif return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i) : hashmap_iterate_in_internal_order(h, i); } bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) { struct hashmap_base_entry *e; void *data; unsigned idx; idx = hashmap_iterate_entry(h, i); if (idx == IDX_NIL) { if (value) *value = NULL; if (key) *key = NULL; return false; } e = bucket_at(h, idx); data = entry_value(h, e); if (value) *value = data; if (key) *key = e->key; return true; } bool set_iterate(Set *s, Iterator *i, void **value) { return internal_hashmap_iterate(HASHMAP_BASE(s), i, value, NULL); } #define HASHMAP_FOREACH_IDX(idx, h, i) \ for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \ (idx != IDX_NIL); \ (idx) = hashmap_iterate_entry((h), &(i))) static void reset_direct_storage(HashmapBase *h) { const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; void *p; assert(!h->has_indirect); p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets); memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); } static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; bool use_pool; use_pool = is_main_thread(); h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); if (!h) return NULL; h->type = type; h->from_pool = use_pool; h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; if (type == HASHMAP_TYPE_ORDERED) { OrderedHashmap *lh = (OrderedHashmap*)h; lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; } reset_direct_storage(h); if (!shared_hash_key_initialized) { random_bytes(shared_hash_key, sizeof(shared_hash_key)); shared_hash_key_initialized= true; } #ifdef ENABLE_DEBUG_HASHMAP h->debug.func = func; h->debug.file = file; h->debug.line = line; assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0); LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug); assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0); #endif return h; } Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); } OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); } Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); } static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *q; assert(h); if (*h) return 0; q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); if (!q) return -ENOMEM; *h = q; return 0; } int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); } int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); } int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); } static void hashmap_free_no_clear(HashmapBase *h) { assert(!h->has_indirect); assert(!h->n_direct_entries); #ifdef ENABLE_DEBUG_HASHMAP assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0); LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug); assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0); #endif if (h->from_pool) mempool_free_tile(hashmap_type_info[h->type].mempool, h); else free(h); } HashmapBase *internal_hashmap_free(HashmapBase *h) { /* Free the hashmap, but nothing in it */ if (h) { internal_hashmap_clear(h); hashmap_free_no_clear(h); } return NULL; } HashmapBase *internal_hashmap_free_free(HashmapBase *h) { /* Free the hashmap and all data objects in it, but not the * keys */ if (h) { internal_hashmap_clear_free(h); hashmap_free_no_clear(h); } return NULL; } Hashmap *hashmap_free_free_free(Hashmap *h) { /* Free the hashmap and all data and key objects in it */ if (h) { hashmap_clear_free_free(h); hashmap_free_no_clear(HASHMAP_BASE(h)); } return NULL; } void internal_hashmap_clear(HashmapBase *h) { if (!h) return; if (h->has_indirect) { free(h->indirect.storage); h->has_indirect = false; } h->n_direct_entries = 0; reset_direct_storage(h); if (h->type == HASHMAP_TYPE_ORDERED) { OrderedHashmap *lh = (OrderedHashmap*) h; lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; } } void internal_hashmap_clear_free(HashmapBase *h) { unsigned idx; if (!h) return; for (idx = skip_free_buckets(h, 0); idx != IDX_NIL; idx = skip_free_buckets(h, idx + 1)) free(entry_value(h, bucket_at(h, idx))); internal_hashmap_clear(h); } void hashmap_clear_free_free(Hashmap *h) { unsigned idx; if (!h) return; for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL; idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) { struct plain_hashmap_entry *e = plain_bucket_at(h, idx); free((void*)e->b.key); free(e->value); } internal_hashmap_clear(HASHMAP_BASE(h)); } static int resize_buckets(HashmapBase *h, unsigned entries_add); /* * Finds an empty bucket to put an entry into, starting the scan at 'idx'. * Performs Robin Hood swaps as it goes. The entry to put must be placed * by the caller into swap slot IDX_PUT. * If used for in-place resizing, may leave a displaced entry in swap slot * IDX_PUT. Caller must rehash it next. * Returns: true if it left a displaced entry to rehash next in IDX_PUT, * false otherwise. */ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx, struct swap_entries *swap) { dib_raw_t raw_dib, *dibs; unsigned dib, distance; #ifdef ENABLE_DEBUG_HASHMAP h->debug.put_count++; #endif dibs = dib_raw_ptr(h); for (distance = 0; ; distance++) { raw_dib = dibs[idx]; if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) { if (raw_dib == DIB_RAW_REHASH) bucket_move_entry(h, swap, idx, IDX_TMP); if (h->has_indirect && h->indirect.idx_lowest_entry > idx) h->indirect.idx_lowest_entry = idx; bucket_set_dib(h, idx, distance); bucket_move_entry(h, swap, IDX_PUT, idx); if (raw_dib == DIB_RAW_REHASH) { bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); return true; } return false; } dib = bucket_calculate_dib(h, idx, raw_dib); if (dib < distance) { /* Found a wealthier entry. Go Robin Hood! */ bucket_set_dib(h, idx, distance); /* swap the entries */ bucket_move_entry(h, swap, idx, IDX_TMP); bucket_move_entry(h, swap, IDX_PUT, idx); bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); distance = dib; } idx = next_idx(h, idx); } } /* * Puts an entry into a hashmap, boldly - no check whether key already exists. * The caller must place the entry (only its key and value, not link indexes) * in swap slot IDX_PUT. * Caller must ensure: the key does not exist yet in the hashmap. * that resize is not needed if !may_resize. * Returns: 1 if entry was put successfully. * -ENOMEM if may_resize==true and resize failed with -ENOMEM. * Cannot return -ENOMEM if !may_resize. */ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, struct swap_entries *swap, bool may_resize) { struct ordered_hashmap_entry *new_entry; int r; assert(idx < n_buckets(h)); new_entry = bucket_at_swap(swap, IDX_PUT); if (may_resize) { r = resize_buckets(h, 1); if (r < 0) return r; if (r > 0) idx = bucket_hash(h, new_entry->p.b.key); } assert(n_entries(h) < n_buckets(h)); if (h->type == HASHMAP_TYPE_ORDERED) { OrderedHashmap *lh = (OrderedHashmap*) h; new_entry->iterate_next = IDX_NIL; new_entry->iterate_previous = lh->iterate_list_tail; if (lh->iterate_list_tail != IDX_NIL) { struct ordered_hashmap_entry *old_tail; old_tail = ordered_bucket_at(lh, lh->iterate_list_tail); assert(old_tail->iterate_next == IDX_NIL); old_tail->iterate_next = IDX_PUT; } lh->iterate_list_tail = IDX_PUT; if (lh->iterate_list_head == IDX_NIL) lh->iterate_list_head = IDX_PUT; } assert_se(hashmap_put_robin_hood(h, idx, swap) == false); n_entries_inc(h); #ifdef ENABLE_DEBUG_HASHMAP h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h)); #endif return 1; } #define hashmap_put_boldly(h, idx, swap, may_resize) \ hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize) /* * Returns 0 if resize is not needed. * 1 if successfully resized. * -ENOMEM on allocation failure. */ static int resize_buckets(HashmapBase *h, unsigned entries_add) { struct swap_entries swap; char *new_storage; dib_raw_t *old_dibs, *new_dibs; const struct hashmap_type_info *hi; unsigned idx, optimal_idx; unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries; uint8_t new_shift; bool rehash_next; assert(h); hi = &hashmap_type_info[h->type]; new_n_entries = n_entries(h) + entries_add; /* overflow? */ if (_unlikely_(new_n_entries < entries_add)) return -ENOMEM; /* For direct storage we allow 100% load, because it's tiny. */ if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets) return 0; /* * Load factor = n/m = 1 - (1/INV_KEEP_FREE). * From it follows: m = n + n/(INV_KEEP_FREE - 1) */ new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1); /* overflow? */ if (_unlikely_(new_n_buckets < new_n_entries)) return -ENOMEM; if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t)))) return -ENOMEM; old_n_buckets = n_buckets(h); if (_likely_(new_n_buckets <= old_n_buckets)) return 0; new_shift = log2u_round_up(MAX( new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)), 2 * sizeof(struct direct_storage))); /* Realloc storage (buckets and DIB array). */ new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL, 1U << new_shift); if (!new_storage) return -ENOMEM; /* Must upgrade direct to indirect storage. */ if (!h->has_indirect) { memcpy(new_storage, h->direct.storage, old_n_buckets * (hi->entry_size + sizeof(dib_raw_t))); h->indirect.n_entries = h->n_direct_entries; h->indirect.idx_lowest_entry = 0; h->n_direct_entries = 0; } /* Get a new hash key. If we've just upgraded to indirect storage, * allow reusing a previously generated key. It's still a different key * from the shared one that we used for direct storage. */ get_hash_key(h->indirect.hash_key, !h->has_indirect); h->has_indirect = true; h->indirect.storage = new_storage; h->indirect.n_buckets = (1U << new_shift) / (hi->entry_size + sizeof(dib_raw_t)); old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets); new_dibs = dib_raw_ptr(h); /* * Move the DIB array to the new place, replacing valid DIB values with * DIB_RAW_REHASH to indicate all of the used buckets need rehashing. * Note: Overlap is not possible, because we have at least doubled the * number of buckets and dib_raw_t is smaller than any entry type. */ for (idx = 0; idx < old_n_buckets; idx++) { assert(old_dibs[idx] != DIB_RAW_REHASH); new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE : DIB_RAW_REHASH; } /* Zero the area of newly added entries (including the old DIB area) */ memzero(bucket_at(h, old_n_buckets), (n_buckets(h) - old_n_buckets) * hi->entry_size); /* The upper half of the new DIB array needs initialization */ memset(&new_dibs[old_n_buckets], DIB_RAW_INIT, (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t)); /* Rehash entries that need it */ n_rehashed = 0; for (idx = 0; idx < old_n_buckets; idx++) { if (new_dibs[idx] != DIB_RAW_REHASH) continue; optimal_idx = bucket_hash(h, bucket_at(h, idx)->key); /* * Not much to do if by luck the entry hashes to its current * location. Just set its DIB. */ if (optimal_idx == idx) { new_dibs[idx] = 0; n_rehashed++; continue; } new_dibs[idx] = DIB_RAW_FREE; bucket_move_entry(h, &swap, idx, IDX_PUT); /* bucket_move_entry does not clear the source */ memzero(bucket_at(h, idx), hi->entry_size); do { /* * Find the new bucket for the current entry. This may make * another entry homeless and load it into IDX_PUT. */ rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap); n_rehashed++; /* Did the current entry displace another one? */ if (rehash_next) optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key); } while (rehash_next); } assert(n_rehashed == n_entries(h)); return 1; } /* * Finds an entry with a matching key * Returns: index of the found entry, or IDX_NIL if not found. */ static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) { struct hashmap_base_entry *e; unsigned dib, distance; dib_raw_t *dibs = dib_raw_ptr(h); assert(idx < n_buckets(h)); for (distance = 0; ; distance++) { if (dibs[idx] == DIB_RAW_FREE) return IDX_NIL; dib = bucket_calculate_dib(h, idx, dibs[idx]); if (dib < distance) return IDX_NIL; if (dib == distance) { e = bucket_at(h, idx); if (h->hash_ops->compare(e->key, key) == 0) return idx; } idx = next_idx(h, idx); } } #define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key) int hashmap_put(Hashmap *h, const void *key, void *value) { struct swap_entries swap; struct plain_hashmap_entry *e; unsigned hash, idx; assert(h); hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx != IDX_NIL) { e = plain_bucket_at(h, idx); if (e->value == value) return 0; return -EEXIST; } e = &bucket_at_swap(&swap, IDX_PUT)->p; e->b.key = key; e->value = value; return hashmap_put_boldly(h, hash, &swap, true); } int set_put(Set *s, const void *key) { struct swap_entries swap; struct hashmap_base_entry *e; unsigned hash, idx; assert(s); hash = bucket_hash(s, key); idx = bucket_scan(s, hash, key); if (idx != IDX_NIL) return 0; e = &bucket_at_swap(&swap, IDX_PUT)->p.b; e->key = key; return hashmap_put_boldly(s, hash, &swap, true); } int hashmap_replace(Hashmap *h, const void *key, void *value) { struct swap_entries swap; struct plain_hashmap_entry *e; unsigned hash, idx; assert(h); hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx != IDX_NIL) { e = plain_bucket_at(h, idx); #ifdef ENABLE_DEBUG_HASHMAP /* Although the key is equal, the key pointer may have changed, * and this would break our assumption for iterating. So count * this operation as incompatible with iteration. */ if (e->b.key != key) { h->b.debug.put_count++; h->b.debug.rem_count++; h->b.debug.last_rem_idx = idx; } #endif e->b.key = key; e->value = value; return 0; } e = &bucket_at_swap(&swap, IDX_PUT)->p; e->b.key = key; e->value = value; return hashmap_put_boldly(h, hash, &swap, true); } int hashmap_update(Hashmap *h, const void *key, void *value) { struct plain_hashmap_entry *e; unsigned hash, idx; assert(h); hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) return -ENOENT; e = plain_bucket_at(h, idx); e->value = value; return 0; } void *internal_hashmap_get(HashmapBase *h, const void *key) { struct hashmap_base_entry *e; unsigned hash, idx; if (!h) return NULL; hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) return NULL; e = bucket_at(h, idx); return entry_value(h, e); } void *hashmap_get2(Hashmap *h, const void *key, void **key2) { struct plain_hashmap_entry *e; unsigned hash, idx; if (!h) return NULL; hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) return NULL; e = plain_bucket_at(h, idx); if (key2) *key2 = (void*) e->b.key; return e->value; } bool internal_hashmap_contains(HashmapBase *h, const void *key) { unsigned hash; if (!h) return false; hash = bucket_hash(h, key); return bucket_scan(h, hash, key) != IDX_NIL; } void *internal_hashmap_remove(HashmapBase *h, const void *key) { struct hashmap_base_entry *e; unsigned hash, idx; void *data; if (!h) return NULL; hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) return NULL; e = bucket_at(h, idx); data = entry_value(h, e); remove_entry(h, idx); return data; } void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) { struct plain_hashmap_entry *e; unsigned hash, idx; void *data; if (!h) { if (rkey) *rkey = NULL; return NULL; } hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) { if (rkey) *rkey = NULL; return NULL; } e = plain_bucket_at(h, idx); data = e->value; if (rkey) *rkey = (void*) e->b.key; remove_entry(h, idx); return data; } int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) { struct swap_entries swap; struct plain_hashmap_entry *e; unsigned old_hash, new_hash, idx; if (!h) return -ENOENT; old_hash = bucket_hash(h, old_key); idx = bucket_scan(h, old_hash, old_key); if (idx == IDX_NIL) return -ENOENT; new_hash = bucket_hash(h, new_key); if (bucket_scan(h, new_hash, new_key) != IDX_NIL) return -EEXIST; remove_entry(h, idx); e = &bucket_at_swap(&swap, IDX_PUT)->p; e->b.key = new_key; e->value = value; assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); return 0; } int set_remove_and_put(Set *s, const void *old_key, const void *new_key) { struct swap_entries swap; struct hashmap_base_entry *e; unsigned old_hash, new_hash, idx; if (!s) return -ENOENT; old_hash = bucket_hash(s, old_key); idx = bucket_scan(s, old_hash, old_key); if (idx == IDX_NIL) return -ENOENT; new_hash = bucket_hash(s, new_key); if (bucket_scan(s, new_hash, new_key) != IDX_NIL) return -EEXIST; remove_entry(s, idx); e = &bucket_at_swap(&swap, IDX_PUT)->p.b; e->key = new_key; assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1); return 0; } int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) { struct swap_entries swap; struct plain_hashmap_entry *e; unsigned old_hash, new_hash, idx_old, idx_new; if (!h) return -ENOENT; old_hash = bucket_hash(h, old_key); idx_old = bucket_scan(h, old_hash, old_key); if (idx_old == IDX_NIL) return -ENOENT; old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key; new_hash = bucket_hash(h, new_key); idx_new = bucket_scan(h, new_hash, new_key); if (idx_new != IDX_NIL) if (idx_old != idx_new) { remove_entry(h, idx_new); /* Compensate for a possible backward shift. */ if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key) idx_old = prev_idx(HASHMAP_BASE(h), idx_old); assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key); } remove_entry(h, idx_old); e = &bucket_at_swap(&swap, IDX_PUT)->p; e->b.key = new_key; e->value = value; assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); return 0; } void *hashmap_remove_value(Hashmap *h, const void *key, void *value) { struct plain_hashmap_entry *e; unsigned hash, idx; if (!h) return NULL; hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) return NULL; e = plain_bucket_at(h, idx); if (e->value != value) return NULL; remove_entry(h, idx); return value; } unsigned internal_hashmap_size(HashmapBase *h) { if (!h) return 0; return n_entries(h); } unsigned internal_hashmap_buckets(HashmapBase *h) { if (!h) return 0; return n_buckets(h); } int internal_hashmap_merge(Hashmap *h, Hashmap *other) { Iterator i; unsigned idx; assert(h); HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { struct plain_hashmap_entry *pe = plain_bucket_at(other, idx); int r; r = hashmap_put(h, pe->b.key, pe->value); if (r < 0 && r != -EEXIST) return r; } return 0; } int set_merge(Set *s, Set *other) { Iterator i; unsigned idx; assert(s); HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { struct set_entry *se = set_bucket_at(other, idx); int r; r = set_put(s, se->b.key); if (r < 0) return r; } return 0; } int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) { int r; assert(h); r = resize_buckets(h, entries_add); if (r < 0) return r; return 0; } /* * The same as hashmap_merge(), but every new item from other is moved to h. * Keys already in h are skipped and stay in other. * Returns: 0 on success. * -ENOMEM on alloc failure, in which case no move has been done. */ int internal_hashmap_move(HashmapBase *h, HashmapBase *other) { struct swap_entries swap; struct hashmap_base_entry *e, *n; Iterator i; unsigned idx; int r; assert(h); if (!other) return 0; assert(other->type == h->type); /* * This reserves buckets for the worst case, where none of other's * entries are yet present in h. This is preferable to risking * an allocation failure in the middle of the moving and having to * rollback or return a partial result. */ r = resize_buckets(h, n_entries(other)); if (r < 0) return r; HASHMAP_FOREACH_IDX(idx, other, i) { unsigned h_hash; e = bucket_at(other, idx); h_hash = bucket_hash(h, e->key); if (bucket_scan(h, h_hash, e->key) != IDX_NIL) continue; n = &bucket_at_swap(&swap, IDX_PUT)->p.b; n->key = e->key; if (h->type != HASHMAP_TYPE_SET) ((struct plain_hashmap_entry*) n)->value = ((struct plain_hashmap_entry*) e)->value; assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1); remove_entry(other, idx); } return 0; } int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) { struct swap_entries swap; unsigned h_hash, other_hash, idx; struct hashmap_base_entry *e, *n; int r; assert(h); h_hash = bucket_hash(h, key); if (bucket_scan(h, h_hash, key) != IDX_NIL) return -EEXIST; if (!other) return -ENOENT; assert(other->type == h->type); other_hash = bucket_hash(other, key); idx = bucket_scan(other, other_hash, key); if (idx == IDX_NIL) return -ENOENT; e = bucket_at(other, idx); n = &bucket_at_swap(&swap, IDX_PUT)->p.b; n->key = e->key; if (h->type != HASHMAP_TYPE_SET) ((struct plain_hashmap_entry*) n)->value = ((struct plain_hashmap_entry*) e)->value; r = hashmap_put_boldly(h, h_hash, &swap, true); if (r < 0) return r; remove_entry(other, idx); return 0; } HashmapBase *internal_hashmap_copy(HashmapBase *h) { HashmapBase *copy; int r; assert(h); copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); if (!copy) return NULL; switch (h->type) { case HASHMAP_TYPE_PLAIN: case HASHMAP_TYPE_ORDERED: r = hashmap_merge((Hashmap*)copy, (Hashmap*)h); break; case HASHMAP_TYPE_SET: r = set_merge((Set*)copy, (Set*)h); break; default: assert_not_reached("Unknown hashmap type"); } if (r < 0) { internal_hashmap_free(copy); return NULL; } return copy; } char **internal_hashmap_get_strv(HashmapBase *h) { char **sv; Iterator i; unsigned idx, n; sv = new(char*, n_entries(h)+1); if (!sv) return NULL; n = 0; HASHMAP_FOREACH_IDX(idx, h, i) sv[n++] = entry_value(h, bucket_at(h, idx)); sv[n] = NULL; return sv; } void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { struct ordered_hashmap_entry *e; unsigned hash, idx; if (!h) return NULL; hash = bucket_hash(h, key); idx = bucket_scan(h, hash, key); if (idx == IDX_NIL) return NULL; e = ordered_bucket_at(h, idx); if (e->iterate_next == IDX_NIL) return NULL; return ordered_bucket_at(h, e->iterate_next)->p.value; } int set_consume(Set *s, void *value) { int r; r = set_put(s, value); if (r <= 0) free(value); return r; } int set_put_strdup(Set *s, const char *p) { char *c; int r; assert(s); assert(p); c = strdup(p); if (!c) return -ENOMEM; r = set_consume(s, c); if (r == -EEXIST) return 0; return r; } int set_put_strdupv(Set *s, char **l) { int n = 0, r; char **i; STRV_FOREACH(i, l) { r = set_put_strdup(s, *i); if (r < 0) return r; n += r; } return n; } systemd-bootchart-233/src/hashmap.h000066400000000000000000000356361315600604400174330ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering Copyright 2014 Michal Schmidt systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" #include "hash-funcs.h" #include "macro.h" /* * A hash table implementation. As a minor optimization a NULL hashmap object * will be treated as empty hashmap for all read operations. That way it is not * necessary to instantiate an object for each Hashmap use. * * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap), * the implemention will: * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py) * - perform extra checks for invalid use of iterators */ #define HASH_KEY_SIZE 16 /* The base type for all hashmap and set types. Many functions in the * implementation take (HashmapBase*) parameters and are run-time polymorphic, * though the API is not meant to be polymorphic (do not call functions * internal_*() directly). */ typedef struct HashmapBase HashmapBase; /* Specific hashmap/set types */ typedef struct Hashmap Hashmap; /* Maps keys to values */ typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */ typedef struct Set Set; /* Stores just keys */ /* Ideally the Iterator would be an opaque struct, but it is instantiated * by hashmap users, so the definition has to be here. Do not use its fields * directly. */ typedef struct { unsigned idx; /* index of an entry to be iterated next */ const void *next_key; /* expected value of that entry's key pointer */ #ifdef ENABLE_DEBUG_HASHMAP unsigned put_count; /* hashmap's put_count recorded at start of iteration */ unsigned rem_count; /* hashmap's rem_count in previous iteration */ unsigned prev_idx; /* idx in previous iteration */ #endif } Iterator; #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) /* Macros for type checking */ #define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \ (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \ __builtin_types_compatible_p(typeof(h), Hashmap*) || \ __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \ __builtin_types_compatible_p(typeof(h), Set*)) #define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \ (__builtin_types_compatible_p(typeof(h), Hashmap*) || \ __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \ #define HASHMAP_BASE(h) \ __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \ (HashmapBase*)(h), \ (void)0) #define PLAIN_HASHMAP(h) \ __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \ (Hashmap*)(h), \ (void)0) #ifdef ENABLE_DEBUG_HASHMAP # define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line # define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__ # define HASHMAP_DEBUG_PASS_ARGS , func, file, line #else # define HASHMAP_DEBUG_PARAMS # define HASHMAP_DEBUG_SRC_ARGS # define HASHMAP_DEBUG_PASS_ARGS #endif Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) HashmapBase *internal_hashmap_free(HashmapBase *h); static inline Hashmap *hashmap_free(Hashmap *h) { return (void*)internal_hashmap_free(HASHMAP_BASE(h)); } static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) { return (void*)internal_hashmap_free(HASHMAP_BASE(h)); } HashmapBase *internal_hashmap_free_free(HashmapBase *h); static inline Hashmap *hashmap_free_free(Hashmap *h) { return (void*)internal_hashmap_free_free(HASHMAP_BASE(h)); } static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) { return (void*)internal_hashmap_free_free(HASHMAP_BASE(h)); } Hashmap *hashmap_free_free_free(Hashmap *h); static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) { return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h)); } HashmapBase *internal_hashmap_copy(HashmapBase *h); static inline Hashmap *hashmap_copy(Hashmap *h) { return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); } static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) { return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); } int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) int hashmap_put(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) { return hashmap_put(PLAIN_HASHMAP(h), key, value); } int hashmap_update(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { return hashmap_update(PLAIN_HASHMAP(h), key, value); } int hashmap_replace(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) { return hashmap_replace(PLAIN_HASHMAP(h), key, value); } void *internal_hashmap_get(HashmapBase *h, const void *key); static inline void *hashmap_get(Hashmap *h, const void *key) { return internal_hashmap_get(HASHMAP_BASE(h), key); } static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) { return internal_hashmap_get(HASHMAP_BASE(h), key); } void *hashmap_get2(Hashmap *h, const void *key, void **rkey); static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) { return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); } bool internal_hashmap_contains(HashmapBase *h, const void *key); static inline bool hashmap_contains(Hashmap *h, const void *key) { return internal_hashmap_contains(HASHMAP_BASE(h), key); } static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) { return internal_hashmap_contains(HASHMAP_BASE(h), key); } void *internal_hashmap_remove(HashmapBase *h, const void *key); static inline void *hashmap_remove(Hashmap *h, const void *key) { return internal_hashmap_remove(HASHMAP_BASE(h), key); } static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) { return internal_hashmap_remove(HASHMAP_BASE(h), key); } void *hashmap_remove2(Hashmap *h, const void *key, void **rkey); static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) { return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); } void *hashmap_remove_value(Hashmap *h, const void *key, void *value); static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); } int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value); } int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value); } /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa * should just work, allow this by having looser type-checking here. */ int internal_hashmap_merge(Hashmap *h, Hashmap *other); #define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other)) #define ordered_hashmap_merge(h, other) hashmap_merge(h, other) int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add); static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) { return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); } static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) { return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); } int internal_hashmap_move(HashmapBase *h, HashmapBase *other); /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */ static inline int hashmap_move(Hashmap *h, Hashmap *other) { return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); } static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) { return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); } int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key); static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); } static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) { return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); } unsigned internal_hashmap_size(HashmapBase *h) _pure_; static inline unsigned hashmap_size(Hashmap *h) { return internal_hashmap_size(HASHMAP_BASE(h)); } static inline unsigned ordered_hashmap_size(OrderedHashmap *h) { return internal_hashmap_size(HASHMAP_BASE(h)); } static inline bool hashmap_isempty(Hashmap *h) { return hashmap_size(h) == 0; } static inline bool ordered_hashmap_isempty(OrderedHashmap *h) { return ordered_hashmap_size(h) == 0; } unsigned internal_hashmap_buckets(HashmapBase *h) _pure_; static inline unsigned hashmap_buckets(Hashmap *h) { return internal_hashmap_buckets(HASHMAP_BASE(h)); } static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) { return internal_hashmap_buckets(HASHMAP_BASE(h)); } bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key); static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) { return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key); } static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) { return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key); } void internal_hashmap_clear(HashmapBase *h); static inline void hashmap_clear(Hashmap *h) { internal_hashmap_clear(HASHMAP_BASE(h)); } static inline void ordered_hashmap_clear(OrderedHashmap *h) { internal_hashmap_clear(HASHMAP_BASE(h)); } void internal_hashmap_clear_free(HashmapBase *h); static inline void hashmap_clear_free(Hashmap *h) { internal_hashmap_clear_free(HASHMAP_BASE(h)); } static inline void ordered_hashmap_clear_free(OrderedHashmap *h) { internal_hashmap_clear_free(HASHMAP_BASE(h)); } void hashmap_clear_free_free(Hashmap *h); static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { hashmap_clear_free_free(PLAIN_HASHMAP(h)); } /* * Note about all *_first*() functions * * For plain Hashmaps and Sets the order of entries is undefined. * The functions find whatever entry is first in the implementation * internal order. * * Only for OrderedHashmaps the order is well defined and finding * the first entry is O(1). */ void *internal_hashmap_steal_first(HashmapBase *h); static inline void *hashmap_steal_first(Hashmap *h) { return internal_hashmap_steal_first(HASHMAP_BASE(h)); } static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) { return internal_hashmap_steal_first(HASHMAP_BASE(h)); } void *internal_hashmap_steal_first_key(HashmapBase *h); static inline void *hashmap_steal_first_key(Hashmap *h) { return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); } static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) { return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); } /* no hashmap_next */ void *ordered_hashmap_next(OrderedHashmap *h, const void *key); char **internal_hashmap_get_strv(HashmapBase *h); static inline char **hashmap_get_strv(Hashmap *h) { return internal_hashmap_get_strv(HASHMAP_BASE(h)); } static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { return internal_hashmap_get_strv(HASHMAP_BASE(h)); } /* * Hashmaps are iterated in unpredictable order. * OrderedHashmaps are an exception to this. They are iterated in the order * the entries were inserted. * It is safe to remove the current entry. */ #define HASHMAP_FOREACH(e, h, i) \ for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); ) #define ORDERED_HASHMAP_FOREACH(e, h, i) \ for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); ) #define HASHMAP_FOREACH_KEY(e, k, h, i) \ for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); ) #define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \ for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); ) DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) #define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) #define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep) #define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep) #define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep) #define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep) systemd-bootchart-233/src/io-util.c000066400000000000000000000054221315600604400173550ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "io-util.h" #include "time-util.h" ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { uint8_t *p = buf; ssize_t n = 0; assert(fd >= 0); assert(buf); /* If called with nbytes == 0, let's call read() at least * once, to validate the operation */ if (nbytes > (size_t) SSIZE_MAX) return -EINVAL; do { ssize_t k; k = read(fd, p, nbytes); if (k < 0) { if (errno == EINTR) continue; if (errno == EAGAIN && do_poll) { /* We knowingly ignore any return value here, * and expect that any error/EOF is reported * via read() */ (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); continue; } return n > 0 ? n : -errno; } if (k == 0) return n; assert((size_t) k <= nbytes); p += k; nbytes -= k; n += k; } while (nbytes > 0); return n; } int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { ssize_t n; n = loop_read(fd, buf, nbytes, do_poll); if (n < 0) return (int) n; if ((size_t) n != nbytes) return -EIO; return 0; } int fd_wait_for_event(int fd, int event, usec_t t) { struct pollfd pollfd = { .fd = fd, .events = event, }; struct timespec ts; int r; r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); if (r < 0) return -errno; if (r == 0) return 0; return pollfd.revents; } systemd-bootchart-233/src/io-util.h000066400000000000000000000051161315600604400173620ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "attributes.h" #include "macro.h" #include "time-util.h" ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); int fd_wait_for_event(int fd, int event, usec_t timeout); #define IOVEC_SET_STRING(i, s) \ do { \ struct iovec *_i = &(i); \ char *_s = (char *)(s); \ _i->iov_base = _s; \ _i->iov_len = strlen(_s); \ } while(false) static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { unsigned j; size_t r = 0; for (j = 0; j < n; j++) r += i[j].iov_len; return r; } static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { unsigned j; for (j = 0; j < n; j++) { size_t sub; if (_unlikely_(k <= 0)) break; sub = MIN(i[j].iov_len, k); i[j].iov_len -= sub; i[j].iov_base = (uint8_t*) i[j].iov_base + sub; k -= sub; } return k; } static inline bool FILE_SIZE_VALID(uint64_t l) { /* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than * 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */ return (l >> 63) == 0; } static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { /* Same as above, but allows one extra value: -1 as indication for infinity. */ if (l == (uint64_t) -1) return true; return FILE_SIZE_VALID(l); } systemd-bootchart-233/src/list.h000066400000000000000000000242731315600604400167600ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ /* The head of the linked list. Use this in the structure that shall * contain the head of the linked list */ #define LIST_HEAD(t,name) \ t *name /* The pointers in the linked list's items. Use this in the item structure */ #define LIST_FIELDS(t,name) \ t *name##_next, *name##_prev /* Initialize the list's head */ #define LIST_HEAD_INIT(head) \ do { \ (head) = NULL; } \ while(false) /* Initialize a list item */ #define LIST_INIT(name,item) \ do { \ typeof(*(item)) *_item = (item); \ assert(_item); \ _item->name##_prev = _item->name##_next = NULL; \ } while(false) /* Prepend an item to the list */ #define LIST_PREPEND(name,head,item) \ do { \ typeof(*(head)) **_head = &(head), *_item = (item); \ assert(_item); \ if ((_item->name##_next = *_head)) \ _item->name##_next->name##_prev = _item; \ _item->name##_prev = NULL; \ *_head = _item; \ } while(false) /* Append an item to the list */ #define LIST_APPEND(name,head,item) \ do { \ typeof(*(head)) *_tail; \ LIST_FIND_TAIL(name,head,_tail); \ LIST_INSERT_AFTER(name,head,_tail,item); \ } while(false) /* Remove an item from the list */ #define LIST_REMOVE(name,head,item) \ do { \ typeof(*(head)) **_head = &(head), *_item = (item); \ assert(_item); \ if (_item->name##_next) \ _item->name##_next->name##_prev = _item->name##_prev; \ if (_item->name##_prev) \ _item->name##_prev->name##_next = _item->name##_next; \ else { \ assert(*_head == _item); \ *_head = _item->name##_next; \ } \ _item->name##_next = _item->name##_prev = NULL; \ } while(false) /* Find the head of the list */ #define LIST_FIND_HEAD(name,item,head) \ do { \ typeof(*(item)) *_item = (item); \ if (!_item) \ (head) = NULL; \ else { \ while (_item->name##_prev) \ _item = _item->name##_prev; \ (head) = _item; \ } \ } while (false) /* Find the tail of the list */ #define LIST_FIND_TAIL(name,item,tail) \ do { \ typeof(*(item)) *_item = (item); \ if (!_item) \ (tail) = NULL; \ else { \ while (_item->name##_next) \ _item = _item->name##_next; \ (tail) = _item; \ } \ } while (false) /* Insert an item after another one (a = where, b = what) */ #define LIST_INSERT_AFTER(name,head,a,b) \ do { \ typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \ assert(_b); \ if (!_a) { \ if ((_b->name##_next = *_head)) \ _b->name##_next->name##_prev = _b; \ _b->name##_prev = NULL; \ *_head = _b; \ } else { \ if ((_b->name##_next = _a->name##_next)) \ _b->name##_next->name##_prev = _b; \ _b->name##_prev = _a; \ _a->name##_next = _b; \ } \ } while(false) /* Insert an item before another one (a = where, b = what) */ #define LIST_INSERT_BEFORE(name,head,a,b) \ do { \ typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \ assert(_b); \ if (!_a) { \ if (!*_head) { \ _b->name##_next = NULL; \ _b->name##_prev = NULL; \ *_head = _b; \ } else { \ typeof(*(head)) *_tail = (head); \ while (_tail->name##_next) \ _tail = _tail->name##_next; \ _b->name##_next = NULL; \ _b->name##_prev = _tail; \ _tail->name##_next = _b; \ } \ } else { \ if ((_b->name##_prev = _a->name##_prev)) \ _b->name##_prev->name##_next = _b; \ _b->name##_next = _a; \ _a->name##_prev = _b; \ } \ } while(false) #define LIST_JUST_US(name,item) \ (!(item)->name##_prev && !(item)->name##_next) \ #define LIST_FOREACH(name,i,head) \ for ((i) = (head); (i); (i) = (i)->name##_next) #define LIST_FOREACH_SAFE(name,i,n,head) \ for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) #define LIST_FOREACH_BEFORE(name,i,p) \ for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) #define LIST_FOREACH_AFTER(name,i,p) \ for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) /* Iterate through all the members of the list p is included in, but skip over p */ #define LIST_FOREACH_OTHERS(name,i,p) \ for (({ \ (i) = (p); \ while ((i) && (i)->name##_prev) \ (i) = (i)->name##_prev; \ if ((i) == (p)) \ (i) = (p)->name##_next; \ }); \ (i); \ (i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next) /* Loop starting from p->next until p->prev. p can be adjusted meanwhile. */ #define LIST_LOOP_BUT_ONE(name,i,head,p) \ for ((i) = (p)->name##_next ? (p)->name##_next : (head); \ (i) != (p); \ (i) = (i)->name##_next ? (i)->name##_next : (head)) systemd-bootchart-233/src/log.c000066400000000000000000000212151315600604400165520ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include #include #include #include #include "sd-messages.h" #include "fd-util.h" #include "io-util.h" #include "log.h" #include "macro.h" #include "stdio-util.h" #include "string-util.h" #include "terminal-util.h" #include "util.h" #define SNDBUF_SIZE (8*1024*1024) static int log_max_level = LOG_INFO; static int console_fd = STDERR_FILENO; /* Akin to glibc's __abort_msg; which is private and we hence cannot * use here. */ static char *log_abort_msg = NULL; static void log_close_console(void) { if (console_fd < 0) return; if (getpid() == 1) { if (console_fd >= 3) safe_close(console_fd); console_fd = -1; } } static int log_open_console(void) { if (console_fd >= 0) return 0; if (getpid() == 1) { console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); if (console_fd < 0) return console_fd; } else console_fd = STDERR_FILENO; return 0; } static int write_to_console( int error, const char *file, int line, const char *func, const char *object_field, const char *object, const char *buffer) { struct iovec iovec[6] = {}; unsigned n = 0; if (console_fd < 0) return 0; IOVEC_SET_STRING(iovec[n++], buffer); IOVEC_SET_STRING(iovec[n++], "\n"); if (writev(console_fd, iovec, n) < 0) { if (errno == EIO && getpid() == 1) { /* If somebody tried to kick us from our * console tty (via vhangup() or suchlike), * try to reconnect */ log_close_console(); log_open_console(); if (console_fd < 0) return 0; if (writev(console_fd, iovec, n) < 0) return -errno; } else return -errno; } return 1; } static int log_dispatch( int error, const char *file, int line, const char *func, const char *object_field, const char *object, char *buffer) { assert(buffer); if (error < 0) error = -error; do { char *e; int k = 0; buffer += strspn(buffer, NEWLINE); if (buffer[0] == 0) break; if ((e = strpbrk(buffer, NEWLINE))) *(e++) = 0; if (k <= 0) (void) write_to_console(error, file, line, func, object_field, object, buffer); buffer = e; } while (buffer); return -error; } int log_internalv( int level, int error, const char *file, int line, const char *func, const char *format, va_list ap) { PROTECT_ERRNO; char buffer[LINE_MAX]; if (error < 0) error = -error; if (_likely_(LOG_PRI(level) > log_max_level)) return -error; /* Make sure that %m maps to the specified error */ if (error != 0) errno = error; vsnprintf(buffer, sizeof(buffer), format, ap); return log_dispatch(error, file, line, func, NULL, NULL, buffer); } int log_internal( int level, int error, const char *file, int line, const char *func, const char *format, ...) { va_list ap; int r; va_start(ap, format); r = log_internalv(level, error, file, line, func, format, ap); va_end(ap); return r; } static void log_assert( int level, const char *text, const char *file, int line, const char *func, const char *format) { static char buffer[LINE_MAX]; if (_likely_(LOG_PRI(level) > log_max_level)) return; DISABLE_WARNING_FORMAT_NONLITERAL; xsprintf(buffer, format, text, file, line, func); REENABLE_WARNING; log_abort_msg = buffer; log_dispatch(0, file, line, func, NULL, NULL, buffer); } noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) { log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); abort(); } noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); abort(); } void log_assert_failed_return(const char *text, const char *file, int line, const char *func) { PROTECT_ERRNO; log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring."); } int log_oom_internal(const char *file, int line, const char *func) { log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory."); return -ENOMEM; } int log_struct_internal( int level, int error, const char *file, int line, const char *func, const char *format, ...) { char buf[LINE_MAX]; bool found = false; PROTECT_ERRNO; va_list ap; if (error < 0) error = -error; if (_likely_(LOG_PRI(level) > log_max_level)) return -error; va_start(ap, format); while (format) { va_list aq; if (error != 0) errno = error; va_copy(aq, ap); vsnprintf(buf, sizeof(buf), format, aq); va_end(aq); if (startswith(buf, "MESSAGE=")) { found = true; break; } VA_FORMAT_ADVANCE(format, ap); format = va_arg(ap, char *); } va_end(ap); if (!found) return -error; return log_dispatch(error, file, line, func, NULL, NULL, buf + 8); } int log_get_max_level(void) { return log_max_level; } int log_syntax_internal( const char *unit, int level, const char *config_file, unsigned config_line, int error, const char *file, int line, const char *func, const char *format, ...) { PROTECT_ERRNO; char buffer[LINE_MAX]; int r; va_list ap; if (error < 0) error = -error; if (_likely_(LOG_PRI(level) > log_max_level)) return -error; if (error != 0) errno = error; va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); va_end(ap); r = log_struct_internal( level, error, file, line, func, #ifdef HAVE_LIBSYSTEMD LOG_MESSAGE_ID(SD_MESSAGE_INVALID_CONFIGURATION), #endif "CONFIG_FILE=%s", config_file, "CONFIG_LINE=%u", config_line, LOG_MESSAGE("[%s:%u] %s", config_file, config_line, buffer), NULL); return r; } systemd-bootchart-233/src/log.h000066400000000000000000000134751315600604400165700ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include "alloc-util.h" #include "attributes.h" int log_get_max_level(void) _pure_; int log_internal( int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(6,7); int log_internalv( int level, int error, const char *file, int line, const char *func, const char *format, va_list ap) _printf_(6,0); int log_struct_internal( int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(6,0) _sentinel_; int log_oom_internal( const char *file, int line, const char *func); /* Logging for various assertions */ noreturn void log_assert_failed( const char *text, const char *file, int line, const char *func); noreturn void log_assert_failed_unreachable( const char *text, const char *file, int line, const char *func); void log_assert_failed_return( const char *text, const char *file, int line, const char *func); /* Logging with level */ #define log_full_errno(level, error, ...) \ ({ \ int _level = (level), _e = (error); \ (log_get_max_level() >= LOG_PRI(_level)) \ ? log_internal(_level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ : -abs(_e); \ }) #define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__) /* Normal logging */ #define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) #define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__) /* Logging triggered by an errno-like error */ #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) #define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__) #define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) #define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__) #ifdef LOG_TRACE # define log_trace(...) log_debug(__VA_ARGS__) #else # define log_trace(...) do {} while(0) #endif #define log_oom() log_oom_internal(__FILE__, __LINE__, __func__) /* Helpers to prepare various fields for structured logging */ #define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ #define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x) int log_syntax_internal( const char *unit, int level, const char *config_file, unsigned config_line, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(9, 10); #define log_syntax(unit, level, config_file, config_line, error, ...) \ ({ \ int _level = (level), _e = (error); \ (log_get_max_level() >= LOG_PRI(_level)) \ ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ : -abs(_e); \ }) #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ ({ \ int _level = (level); \ if (log_get_max_level() >= LOG_PRI(_level)) { \ _cleanup_free_ char *_p = NULL; \ _p = utf8_escape_invalid(rvalue); \ log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ } \ -EINVAL; \ }) systemd-bootchart-233/src/macro.h000066400000000000000000000376111315600604400171060ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "attributes.h" #include "log.h" /* Temporarily disable some warnings */ #define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") #define DISABLE_WARNING_FORMAT_NONLITERAL \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") #define DISABLE_WARNING_MISSING_PROTOTYPES \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") #define DISABLE_WARNING_NONNULL \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wnonnull\"") #define DISABLE_WARNING_SHADOW \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wshadow\"") #define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"") #define REENABLE_WARNING \ _Pragma("GCC diagnostic pop") /* automake test harness */ #define EXIT_TEST_SKIP 77 #define XSTRINGIFY(x) #x #define STRINGIFY(x) XSTRINGIFY(x) #define XCONCATENATE(x, y) x ## y #define CONCATENATE(x, y) XCONCATENATE(x, y) #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ /* Rounds up */ #define ALIGN4(l) (((l) + 3) & ~3) #define ALIGN8(l) (((l) + 7) & ~7) #if __SIZEOF_POINTER__ == 8 #define ALIGN(l) ALIGN8(l) #elif __SIZEOF_POINTER__ == 4 #define ALIGN(l) ALIGN4(l) #else #error "Wut? Pointers are neither 4 nor 8 bytes long?" #endif #define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p))) #define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p))) #define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) static inline size_t ALIGN_TO(size_t l, size_t ali) { return ((l + ali - 1) & ~(ali - 1)); } #define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali))) /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ static inline unsigned long ALIGN_POWER2(unsigned long u) { /* clz(0) is undefined */ if (u == 1) return 1; /* left-shift overflow is undefined */ if (__builtin_clzl(u - 1UL) < 1) return 0; return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); } #define ELEMENTSOF(x) \ __extension__ (__builtin_choose_expr( \ !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ sizeof(x)/sizeof((x)[0]), \ (void)0)) /* * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. */ #define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member) #define __container_of(uniq, ptr, type, member) \ __extension__ ({ \ const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \ (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \ }) #undef MAX #define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) #define __MAX(aq, a, bq, b) \ __extension__ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ }) /* evaluates to (void) if _A or _B are not constant or of different types */ #define CONST_MAX(_A, _B) \ __extension__ (__builtin_choose_expr( \ __builtin_constant_p(_A) && \ __builtin_constant_p(_B) && \ __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ ((_A) > (_B)) ? (_A) : (_B), \ (void)0)) /* takes two types and returns the size of the larger one */ #define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) #define MAX3(x,y,z) \ __extension__ ({ \ const typeof(x) _c = MAX(x,y); \ MAX(_c, z); \ }) #undef MIN #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) #define __MIN(aq, a, bq, b) \ __extension__ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ }) #define MIN3(x,y,z) \ __extension__ ({ \ const typeof(x) _c = MIN(x,y); \ MIN(_c, z); \ }) #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) #define __LESS_BY(aq, a, bq, b) \ __extension__ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) - UNIQ_T(B,bq) : 0; \ }) #undef CLAMP #define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) #define __CLAMP(xq, x, lowq, low, highq, high) \ __extension__ ({ \ const typeof(x) UNIQ_T(X,xq) = (x); \ const typeof(low) UNIQ_T(LOW,lowq) = (low); \ const typeof(high) UNIQ_T(HIGH,highq) = (high); \ UNIQ_T(X,xq) > UNIQ_T(HIGH,highq) ? \ UNIQ_T(HIGH,highq) : \ UNIQ_T(X,xq) < UNIQ_T(LOW,lowq) ? \ UNIQ_T(LOW,lowq) : \ UNIQ_T(X,xq); \ }) /* [(x + y - 1) / y] suffers from an integer overflow, even though the * computation should be possible in the given type. Therefore, we use * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the * quotient and the remainder, so both should be equally fast. */ #define DIV_ROUND_UP(_x, _y) \ __extension__ ({ \ const typeof(_x) __x = (_x); \ const typeof(_y) __y = (_y); \ (__x / __y + !!(__x % __y)); \ }) #define assert_message_se(expr, message) \ do { \ if (_unlikely_(!(expr))) \ log_assert_failed(message, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ } while (false) #define assert_se(expr) assert_message_se(expr, #expr) /* We override the glibc assert() here. */ #undef assert #ifdef NDEBUG #define assert(expr) do {} while(false) #else #define assert(expr) assert_message_se(expr, #expr) #endif #define assert_not_reached(t) \ do { \ log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ } while (false) #if defined(static_assert) /* static_assert() is sometimes defined in a way that trips up * -Wdeclaration-after-statement, hence let's temporarily turn off * this warning around it. */ #define assert_cc(expr) \ DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ static_assert(expr, #expr); \ REENABLE_WARNING #else #define assert_cc(expr) \ DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ struct CONCATENATE(_assert_struct_, __COUNTER__) { \ char x[(expr) ? 0 : -1]; \ }; \ REENABLE_WARNING #endif #define assert_log(expr, message) ((_likely_(expr)) \ ? (true) \ : (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false)) #define assert_return(expr, r) \ do { \ if (!assert_log(expr, #expr)) \ return (r); \ } while (false) #define assert_return_errno(expr, r, err) \ do { \ if (!assert_log(expr, #expr)) { \ errno = err; \ return (r); \ } \ } while (false) #define PTR_TO_INT(p) ((int) ((intptr_t) (p))) #define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) #define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) #define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) #define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) #define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) #define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) #define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) #define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define CHAR_TO_STR(x) ((char[2]) { x, 0 }) #define char_array_0(x) x[sizeof(x)-1] = 0; /* Returns the number of chars needed to format variables of the * specified type as a decimal string. Adds in extra space for a * negative '-' prefix (hence works correctly on signed * types). Includes space for the trailing NUL. */ #define DECIMAL_STR_MAX(type) \ (2+(sizeof(type) <= 1 ? 3 : \ sizeof(type) <= 2 ? 5 : \ sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) #define DECIMAL_STR_WIDTH(x) \ ({ \ typeof(x) _x_ = (x); \ unsigned ans = 1; \ while (_x_ /= 10) \ ans++; \ ans; \ }) #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) #define CASE_F(X) case X: #define CASE_F_1(CASE, X) CASE_F(X) #define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) #define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) #define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__) #define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__) #define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__) #define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__) #define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__) #define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__) #define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__) #define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__) #define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__) #define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__) #define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__) #define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__) #define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__) #define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__) #define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__) #define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__) #define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__) #define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME #define FOR_EACH_MAKE_CASE(...) \ GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ (CASE_F,__VA_ARGS__) #define IN_SET(x, ...) \ ({ \ bool _found = false; \ /* If the build breaks in the line below, you need to extend the case macros */ \ static _unused_ char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \ switch(x) { \ FOR_EACH_MAKE_CASE(__VA_ARGS__) \ _found = true; \ break; \ default: \ break; \ } \ _found; \ }) #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ func(*p); \ } \ struct __useless_struct_to_allow_trailing_semicolon__ systemd-bootchart-233/src/mempool.c000066400000000000000000000054261315600604400174470ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010-2014 Lennart Poettering Copyright 2014 Michal Schmidt systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include "attributes.h" #include "macro.h" #include "mempool.h" #include "util.h" struct pool { struct pool *next; unsigned n_tiles; unsigned n_used; }; void* mempool_alloc_tile(struct mempool *mp) { unsigned i; /* When a tile is released we add it to the list and simply * place the next pointer at its offset 0. */ assert(mp->tile_size >= sizeof(void*)); assert(mp->at_least > 0); if (mp->freelist) { void *r; r = mp->freelist; mp->freelist = * (void**) mp->freelist; return r; } if (_unlikely_(!mp->first_pool) || _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { unsigned n; size_t size; struct pool *p; n = mp->first_pool ? mp->first_pool->n_tiles : 0; n = MAX(mp->at_least, n * 2); size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size); n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size; p = malloc(size); if (!p) return NULL; p->next = mp->first_pool; p->n_tiles = n; p->n_used = 0; mp->first_pool = p; } i = mp->first_pool->n_used++; return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size; } void* mempool_alloc0_tile(struct mempool *mp) { void *p; p = mempool_alloc_tile(mp); if (p) memzero(p, mp->tile_size); return p; } void mempool_free_tile(struct mempool *mp, void *p) { * (void**) p = mp->freelist; mp->freelist = p; } #ifdef VALGRIND void mempool_drop(struct mempool *mp) { struct pool *p = mp->first_pool; while (p) { struct pool *n; n = p->next; free(p); p = n; } } #endif systemd-bootchart-233/src/mempool.h000066400000000000000000000024621315600604400174510ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2011-2014 Lennart Poettering Copyright 2014 Michal Schmidt systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include struct pool; struct mempool { struct pool *first_pool; void *freelist; size_t tile_size; unsigned at_least; }; void* mempool_alloc_tile(struct mempool *mp); void* mempool_alloc0_tile(struct mempool *mp); void mempool_free_tile(struct mempool *mp, void *p); #define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \ static struct mempool pool_name = { \ .tile_size = sizeof(tile_type), \ .at_least = alloc_at_least, \ } #ifdef VALGRIND void mempool_drop(struct mempool *mp); #endif systemd-bootchart-233/src/missing.h000066400000000000000000000026021315600604400174460ustar00rootroot00000000000000#pragma once #include #include #ifndef CGROUP_SUPER_MAGIC #define CGROUP_SUPER_MAGIC 0x27e0eb #endif #ifndef TMPFS_MAGIC #define TMPFS_MAGIC 0x01021994 #endif #if !HAVE_DECL_GETTID static inline pid_t gettid(void) { return (pid_t) syscall(SYS_gettid); } #endif #ifndef __NR_getrandom # if defined __x86_64__ # define __NR_getrandom 318 # elif defined(__i386__) # define __NR_getrandom 355 # elif defined(__arm__) # define __NR_getrandom 384 # elif defined(__aarch64__) # define __NR_getrandom 278 # elif defined(__ia64__) # define __NR_getrandom 1339 # elif defined(__m68k__) # define __NR_getrandom 352 # elif defined(__s390x__) # define __NR_getrandom 349 # elif defined(__powerpc__) # define __NR_getrandom 359 # elif defined _MIPS_SIM # if _MIPS_SIM == _MIPS_SIM_ABI32 # define __NR_getrandom 4353 # endif # if _MIPS_SIM == _MIPS_SIM_NABI32 # define __NR_getrandom 6317 # endif # if _MIPS_SIM == _MIPS_SIM_ABI64 # define __NR_getrandom 5313 # endif # else # warning "__NR_getrandom unknown for your architecture" # define __NR_getrandom 0xffffffff # endif #endif #if !HAVE_DECL_GETRANDOM static inline int getrandom(void *buffer, size_t count, unsigned flags) { return syscall(__NR_getrandom, buffer, count, flags); } #endif #ifndef GRND_NONBLOCK #define GRND_NONBLOCK 0x0001 #endif systemd-bootchart-233/src/parse-util.c000066400000000000000000000127061315600604400200630ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include "macro.h" #include "parse-util.h" #include "string-util.h" int parse_boolean(const char *v) { assert(v); if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) return 1; else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) return 0; return -EINVAL; } int safe_atou(const char *s, unsigned *ret_u) { char *x = NULL; unsigned long l; assert(s); assert(ret_u); /* strtoul() is happy to parse negative values, and silently * converts them to unsigned values without generating an * error. We want a clean error, hence let's look for the "-" * prefix on our own, and generate an error. But let's do so * only after strtoul() validated that the string is clean * otherwise, so that we return EINVAL preferably over * ERANGE. */ s += strspn(s, WHITESPACE); errno = 0; l = strtoul(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; if (s[0] == '-') return -ERANGE; if ((unsigned long) (unsigned) l != l) return -ERANGE; *ret_u = (unsigned) l; return 0; } int safe_atoi(const char *s, int *ret_i) { char *x = NULL; long l; assert(s); assert(ret_i); errno = 0; l = strtol(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; if ((long) (int) l != l) return -ERANGE; *ret_i = (int) l; return 0; } int safe_atollu(const char *s, long long unsigned *ret_llu) { char *x = NULL; unsigned long long l; assert(s); assert(ret_llu); s += strspn(s, WHITESPACE); errno = 0; l = strtoull(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; if (*s == '-') return -ERANGE; *ret_llu = l; return 0; } int safe_atolli(const char *s, long long int *ret_lli) { char *x = NULL; long long l; assert(s); assert(ret_lli); errno = 0; l = strtoll(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; *ret_lli = l; return 0; } int safe_atou8(const char *s, uint8_t *ret) { char *x = NULL; unsigned long l; assert(s); assert(ret); s += strspn(s, WHITESPACE); errno = 0; l = strtoul(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; if (s[0] == '-') return -ERANGE; if ((unsigned long) (uint8_t) l != l) return -ERANGE; *ret = (uint8_t) l; return 0; } int safe_atou16(const char *s, uint16_t *ret) { char *x = NULL; unsigned long l; assert(s); assert(ret); s += strspn(s, WHITESPACE); errno = 0; l = strtoul(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; if (s[0] == '-') return -ERANGE; if ((unsigned long) (uint16_t) l != l) return -ERANGE; *ret = (uint16_t) l; return 0; } int safe_atoi16(const char *s, int16_t *ret) { char *x = NULL; long l; assert(s); assert(ret); errno = 0; l = strtol(s, &x, 0); if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; if ((long) (int16_t) l != l) return -ERANGE; *ret = (int16_t) l; return 0; } int safe_atod(const char *s, double *ret_d) { char *x = NULL; double d = 0; locale_t loc; assert(s); assert(ret_d); loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); if (loc == (locale_t) 0) return -errno; errno = 0; d = strtod_l(s, &x, loc); if (errno > 0) { freelocale(loc); return -errno; } if (!x || x == s || *x) { freelocale(loc); return -EINVAL; } freelocale(loc); *ret_d = (double) d; return 0; } systemd-bootchart-233/src/parse-util.h000066400000000000000000000053311315600604400200640ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" #include "macro.h" #define MODE_INVALID ((mode_t) -1) int parse_boolean(const char *v) _pure_; int safe_atou(const char *s, unsigned *ret_u); int safe_atoi(const char *s, int *ret_i); int safe_atollu(const char *s, unsigned long long *ret_u); int safe_atolli(const char *s, long long int *ret_i); int safe_atou8(const char *s, uint8_t *ret); int safe_atou16(const char *s, uint16_t *ret); int safe_atoi16(const char *s, int16_t *ret); static inline int safe_atou32(const char *s, uint32_t *ret_u) { assert_cc(sizeof(uint32_t) == sizeof(unsigned)); return safe_atou(s, (unsigned*) ret_u); } static inline int safe_atoi32(const char *s, int32_t *ret_i) { assert_cc(sizeof(int32_t) == sizeof(int)); return safe_atoi(s, (int*) ret_i); } static inline int safe_atou64(const char *s, uint64_t *ret_u) { assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); return safe_atollu(s, (unsigned long long*) ret_u); } static inline int safe_atoi64(const char *s, int64_t *ret_i) { assert_cc(sizeof(int64_t) == sizeof(long long int)); return safe_atolli(s, (long long int*) ret_i); } #if LONG_MAX == INT_MAX static inline int safe_atolu(const char *s, unsigned long *ret_u) { assert_cc(sizeof(unsigned long) == sizeof(unsigned)); return safe_atou(s, (unsigned*) ret_u); } static inline int safe_atoli(const char *s, long int *ret_u) { assert_cc(sizeof(long int) == sizeof(int)); return safe_atoi(s, (int*) ret_u); } #else static inline int safe_atolu(const char *s, unsigned long *ret_u) { assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); return safe_atollu(s, (unsigned long long*) ret_u); } static inline int safe_atoli(const char *s, long int *ret_u) { assert_cc(sizeof(long int) == sizeof(long long int)); return safe_atolli(s, (long long int*) ret_u); } #endif int safe_atod(const char *s, double *ret_d); systemd-bootchart-233/src/path-util.c000066400000000000000000000170451315600604400177060ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010-2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "alloc-util.h" #include "macro.h" #include "path-util.h" #include "string-util.h" #include "strv.h" bool path_is_absolute(const char *p) { return p[0] == '/'; } char **path_strv_resolve(char **l, const char *prefix) { char **s; unsigned k = 0; bool enomem = false; if (strv_isempty(l)) return l; /* Goes through every item in the string list and canonicalize * the path. This works in place and won't rollback any * changes on failure. */ STRV_FOREACH(s, l) { char *t, *u; _cleanup_free_ char *orig = NULL; if (!path_is_absolute(*s)) { free(*s); continue; } if (prefix) { orig = *s; t = strappend(prefix, orig); if (!t) { enomem = true; continue; } } else t = *s; errno = 0; u = canonicalize_file_name(t); if (!u) { if (errno == ENOENT) { if (prefix) { u = orig; orig = NULL; free(t); } else u = t; } else { free(t); if (errno == ENOMEM || errno == 0) enomem = true; continue; } } else if (prefix) { char *x; free(t); x = path_startswith(u, prefix); if (x) { /* restore the slash if it was lost */ if (!startswith(x, "/")) *(--x) = '/'; t = strdup(x); free(u); if (!t) { enomem = true; continue; } u = t; } else { /* canonicalized path goes outside of * prefix, keep the original path instead */ free(u); u = orig; orig = NULL; } } else free(t); l[k++] = u; } l[k] = NULL; if (enomem) return NULL; return l; } char **path_strv_resolve_uniq(char **l, const char *prefix) { if (strv_isempty(l)) return l; if (!path_strv_resolve(l, prefix)) return NULL; return strv_uniq(l); } char *path_kill_slashes(char *path) { char *f, *t; bool slash = false; /* Removes redundant inner and trailing slashes. Modifies the * passed string in-place. * * ///foo///bar/ becomes /foo/bar */ for (f = path, t = path; *f; f++) { if (*f == '/') { slash = true; continue; } if (slash) { slash = false; *(t++) = '/'; } *(t++) = *f; } /* Special rule, if we are talking of the root directory, a trailing slash is good */ if (t == path && slash) *(t++) = '/'; *t = 0; return path; } char* path_startswith(const char *path, const char *prefix) { assert(path); assert(prefix); if ((path[0] == '/') != (prefix[0] == '/')) return NULL; for (;;) { size_t a, b; path += strspn(path, "/"); prefix += strspn(prefix, "/"); if (*prefix == 0) return (char*) path; if (*path == 0) return NULL; a = strcspn(path, "/"); b = strcspn(prefix, "/"); if (a != b) return NULL; if (memcmp(path, prefix, a) != 0) return NULL; path += a; prefix += b; } } int path_compare(const char *a, const char *b) { int d; assert(a); assert(b); /* A relative path and an abolute path must not compare as equal. * Which one is sorted before the other does not really matter. * Here a relative path is ordered before an absolute path. */ d = (a[0] == '/') - (b[0] == '/'); if (d != 0) return d; for (;;) { size_t j, k; a += strspn(a, "/"); b += strspn(b, "/"); if (*a == 0 && *b == 0) return 0; /* Order prefixes first: "/foo" before "/foo/bar" */ if (*a == 0) return -1; if (*b == 0) return 1; j = strcspn(a, "/"); k = strcspn(b, "/"); /* Alphabetical sort: "/foo/aaa" before "/foo/b" */ d = memcmp(a, b, MIN(j, k)); if (d != 0) return (d > 0) - (d < 0); /* sign of d */ /* Sort "/foo/a" before "/foo/aaa" */ d = (j > k) - (j < k); /* sign of (j - k) */ if (d != 0) return d; a += j; b += k; } } bool path_equal(const char *a, const char *b) { return path_compare(a, b) == 0; } char *file_in_same_dir(const char *path, const char *filename) { char *e, *ret; size_t k; assert(path); assert(filename); /* This removes the last component of path and appends * filename, unless the latter is absolute anyway or the * former isn't */ if (path_is_absolute(filename)) return strdup(filename); e = strrchr(path, '/'); if (!e) return strdup(filename); k = strlen(filename); ret = new(char, (e + 1 - path) + k + 1); if (!ret) return NULL; memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); return ret; } systemd-bootchart-233/src/path-util.h000066400000000000000000000076621315600604400177170ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010-2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" #define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" #ifdef HAVE_SPLIT_USR # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR #else # define DEFAULT_PATH DEFAULT_PATH_NORMAL #endif bool is_path(const char *p) _pure_; bool path_is_absolute(const char *p) _pure_; char* path_kill_slashes(char *path); char* path_startswith(const char *path, const char *prefix) _pure_; int path_compare(const char *a, const char *b) _pure_; bool path_equal(const char *a, const char *b) _pure_; char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix); /* Iterates through the path prefixes of the specified path, going up * the tree, to root. Also returns "" (and not "/"!) for the root * directory. Excludes the specified directory itself */ #define PATH_FOREACH_PREFIX(prefix, path) \ for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ #define PATH_FOREACH_PREFIX_MORE(prefix, path) \ for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) /* Similar to prefix_root(), but returns an alloca() buffer, or * possibly a const pointer into the path parameter */ #define prefix_roota(root, path) \ ({ \ const char* _path = (path), *_root = (root), *_ret; \ char *_p, *_n; \ size_t _l; \ while (_path[0] == '/' && _path[1] == '/') \ _path ++; \ if (isempty(_root) || path_equal(_root, "/")) \ _ret = _path; \ else { \ _l = strlen(_root) + 1 + strlen(_path) + 1; \ _n = alloca(_l); \ _p = stpcpy(_n, _root); \ while (_p > _n && _p[-1] == '/') \ _p--; \ if (_path[0] != '/') \ *(_p++) = '/'; \ strcpy(_p, _path); \ _ret = _n; \ } \ _ret; \ }) char *file_in_same_dir(const char *path, const char *filename); systemd-bootchart-233/src/process-util.c000066400000000000000000000051461315600604400204270ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include #include #ifdef HAVE_VALGRIND_VALGRIND_H #include #endif #include "fd-util.h" #include "macro.h" #include "missing.h" #include "process-util.h" int getenv_for_pid(pid_t pid, const char *field, char **_value) { _cleanup_fclose_ FILE *f = NULL; char *value = NULL; int r; bool done = false; size_t l; const char *path; assert(pid >= 0); assert(field); assert(_value); path = procfs_file_alloca(pid, "environ"); f = fopen(path, "re"); if (!f) { if (errno == ENOENT) return -ESRCH; return -errno; } l = strlen(field); r = 0; do { char line[LINE_MAX]; unsigned i; for (i = 0; i < sizeof(line)-1; i++) { int c; c = getc(f); if (_unlikely_(c == EOF)) { done = true; break; } else if (c == 0) break; line[i] = c; } line[i] = 0; if (memcmp(line, field, l) == 0 && line[l] == '=') { value = strdup(line + l + 1); if (!value) return -ENOMEM; r = 1; break; } } while (!done); *_value = value; return r; } bool is_main_thread(void) { static thread_local int cached = 0; if (_unlikely_(cached == 0)) cached = getpid() == gettid() ? 1 : -1; return cached > 0; } systemd-bootchart-233/src/process-util.h000066400000000000000000000045611315600604400204340ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include "attributes.h" #include "formats-util.h" #include "macro.h" #define procfs_file_alloca(pid, field) \ ({ \ pid_t _pid_ = (pid); \ const char *_r_; \ if (_pid_ == 0) { \ _r_ = ("/proc/self/" field); \ } else { \ _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ } \ _r_; \ }) int getenv_for_pid(pid_t pid, const char *field, char **_value); bool pid_is_alive(pid_t pid); bool is_main_thread(void); #ifndef PERSONALITY_INVALID /* personality(7) documents that 0xffffffffUL is used for querying the * current personality, hence let's use that here as error * indicator. */ #define PERSONALITY_INVALID 0xffffffffLU #endif int ioprio_class_to_string_alloc(int i, char **s); int ioprio_class_from_string(const char *s); const char *sigchld_code_to_string(int i) _const_; int sigchld_code_from_string(const char *s) _pure_; #define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) #define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) systemd-bootchart-233/src/random-util.c000066400000000000000000000101261315600604400202230ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include #ifdef HAVE_SYS_AUXV_H #include #endif #include "fd-util.h" #include "io-util.h" #include "missing.h" #include "random-util.h" #include "time-util.h" int dev_urandom(void *p, size_t n) { static int have_syscall = -1; _cleanup_close_ int fd = -1; int r; /* Gathers some randomness from the kernel. This call will * never block, and will always return some data from the * kernel, regardless if the random pool is fully initialized * or not. It thus makes no guarantee for the quality of the * returned entropy, but is good enough for or usual usecases * of seeding the hash functions for hashtable */ /* Use the getrandom() syscall unless we know we don't have * it, or when the requested size is too large for it. */ if (have_syscall != 0 || (size_t) (int) n != n) { r = getrandom(p, n, GRND_NONBLOCK); if (r == (int) n) { have_syscall = true; return 0; } if (r < 0) { if (errno == ENOSYS) /* we lack the syscall, continue with * reading from /dev/urandom */ have_syscall = false; else if (errno == EAGAIN) /* not enough entropy for now. Let's * remember to use the syscall the * next time, again, but also read * from /dev/urandom for now, which * doesn't care about the current * amount of entropy. */ have_syscall = true; else return -errno; } else /* too short read? */ return -ENODATA; } fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return errno == ENOENT ? -ENOSYS : -errno; return loop_read_exact(fd, p, n, true); } void initialize_srand(void) { static bool srand_called = false; unsigned x; #ifdef HAVE_SYS_AUXV_H void *auxv; #endif if (srand_called) return; #ifdef HAVE_SYS_AUXV_H /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed the * pseudo-random generator. It's better than nothing... */ auxv = (void*) getauxval(AT_RANDOM); if (auxv) { assert_cc(sizeof(x) < 16); memcpy(&x, auxv, sizeof(x)); } else #endif x = 0; x ^= (unsigned) now(CLOCK_REALTIME); x ^= (unsigned) gettid(); srand(x); srand_called = true; } void random_bytes(void *p, size_t n) { uint8_t *q; int r; r = dev_urandom(p, n); if (r >= 0) return; /* If some idiot made /dev/urandom unavailable to us, he'll * get a PRNG instead. */ initialize_srand(); for (q = p; q < (uint8_t*) p + n; q ++) *q = rand(); } systemd-bootchart-233/src/random-util.h000066400000000000000000000021351315600604400202310ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include int dev_urandom(void *p, size_t n); void random_bytes(void *p, size_t n); void initialize_srand(void); static inline uint64_t random_u64(void) { uint64_t u; random_bytes(&u, sizeof(u)); return u; } static inline uint32_t random_u32(void) { uint32_t u; random_bytes(&u, sizeof(u)); return u; } systemd-bootchart-233/src/sd-messages.h000066400000000000000000000021421315600604400202070ustar00rootroot00000000000000#ifndef foosdmessageshfoo #define foosdmessageshfoo /*** This file is part of systemd. Copyright 2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #ifdef HAVE_LIBSYSTEMD #include #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; #define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01) #define SD_MESSAGE_BOOTCHART SD_ID128_MAKE(9f,26,aa,56,2c,f4,40,c2,b1,6c,77,3d,04,79,b5,18) _SD_END_DECLARATIONS; #endif #endif systemd-bootchart-233/src/set.h000066400000000000000000000073621315600604400166000ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include "hashmap.h" #include "macro.h" Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) static inline Set *set_free(Set *s) { internal_hashmap_free(HASHMAP_BASE(s)); return NULL; } static inline Set *set_free_free(Set *s) { internal_hashmap_free_free(HASHMAP_BASE(s)); return NULL; } /* no set_free_free_free */ static inline Set *set_copy(Set *s) { return (Set*) internal_hashmap_copy(HASHMAP_BASE(s)); } int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) int set_put(Set *s, const void *key); /* no set_update */ /* no set_replace */ static inline void *set_get(Set *s, void *key) { return internal_hashmap_get(HASHMAP_BASE(s), key); } /* no set_get2 */ static inline bool set_contains(Set *s, const void *key) { return internal_hashmap_contains(HASHMAP_BASE(s), key); } static inline void *set_remove(Set *s, const void *key) { return internal_hashmap_remove(HASHMAP_BASE(s), key); } /* no set_remove2 */ /* no set_remove_value */ int set_remove_and_put(Set *s, const void *old_key, const void *new_key); /* no set_remove_and_replace */ int set_merge(Set *s, Set *other); static inline int set_reserve(Set *h, unsigned entries_add) { return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); } static inline int set_move(Set *s, Set *other) { return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other)); } static inline int set_move_one(Set *s, Set *other, const void *key) { return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key); } static inline unsigned set_size(Set *s) { return internal_hashmap_size(HASHMAP_BASE(s)); } static inline bool set_isempty(Set *s) { return set_size(s) == 0; } static inline unsigned set_buckets(Set *s) { return internal_hashmap_buckets(HASHMAP_BASE(s)); } bool set_iterate(Set *s, Iterator *i, void **value); static inline void set_clear(Set *s) { internal_hashmap_clear(HASHMAP_BASE(s)); } static inline void set_clear_free(Set *s) { internal_hashmap_clear_free(HASHMAP_BASE(s)); } /* no set_clear_free_free */ static inline void *set_steal_first(Set *s) { return internal_hashmap_steal_first(HASHMAP_BASE(s)); } /* no set_steal_first_key */ /* no set_first_key */ /* no set_next */ static inline char **set_get_strv(Set *s) { return internal_hashmap_get_strv(HASHMAP_BASE(s)); } int set_consume(Set *s, void *value); int set_put_strdup(Set *s, const char *p); int set_put_strdupv(Set *s, char **l); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) #define _cleanup_set_free_free_ _cleanup_(set_free_freep) systemd-bootchart-233/src/siphash24.c000066400000000000000000000156011315600604400176000ustar00rootroot00000000000000/* SipHash reference C implementation Written in 2012 by Jean-Philippe Aumasson Daniel J. Bernstein To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) (Refactored by Tom Gundersen to split up in several functions and follow systemd coding style) */ #include "macro.h" #include "siphash24.h" #include "unaligned.h" static inline uint64_t rotate_left(uint64_t x, uint8_t b) { assert(b < 64); return (x << b) | (x >> (64 - b)); } static inline void sipround(struct siphash *state) { assert(state); state->v0 += state->v1; state->v1 = rotate_left(state->v1, 13); state->v1 ^= state->v0; state->v0 = rotate_left(state->v0, 32); state->v2 += state->v3; state->v3 = rotate_left(state->v3, 16); state->v3 ^= state->v2; state->v0 += state->v3; state->v3 = rotate_left(state->v3, 21); state->v3 ^= state->v0; state->v2 += state->v1; state->v1 = rotate_left(state->v1, 17); state->v1 ^= state->v2; state->v2 = rotate_left(state->v2, 32); } void siphash24_init(struct siphash *state, const uint8_t k[16]) { uint64_t k0, k1; assert(state); assert(k); k0 = unaligned_read_le64(k); k1 = unaligned_read_le64(k + 8); *state = (struct siphash) { /* "somepseudorandomlygeneratedbytes" */ .v0 = 0x736f6d6570736575ULL ^ k0, .v1 = 0x646f72616e646f6dULL ^ k1, .v2 = 0x6c7967656e657261ULL ^ k0, .v3 = 0x7465646279746573ULL ^ k1, .padding = 0, .inlen = 0, }; } void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { const uint8_t *in = _in; const uint8_t *end = in + inlen; size_t left = state->inlen & 7; uint64_t m; assert(in); assert(state); /* Update total length */ state->inlen += inlen; /* If padding exists, fill it out */ if (left > 0) { for ( ; in < end && left < 8; in ++, left ++) state->padding |= ((uint64_t) *in) << (left * 8); if (in == end && left < 8) /* We did not have enough input to fill out the padding completely */ return; #ifdef DEBUG printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding); #endif state->v3 ^= state->padding; sipround(state); sipround(state); state->v0 ^= state->padding; state->padding = 0; } end -= (state->inlen % sizeof(uint64_t)); for ( ; in < end; in += 8) { m = unaligned_read_le64(in); #ifdef DEBUG printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m); #endif state->v3 ^= m; sipround(state); sipround(state); state->v0 ^= m; } left = state->inlen & 7; switch (left) { case 7: state->padding |= ((uint64_t) in[6]) << 48; case 6: state->padding |= ((uint64_t) in[5]) << 40; case 5: state->padding |= ((uint64_t) in[4]) << 32; case 4: state->padding |= ((uint64_t) in[3]) << 24; case 3: state->padding |= ((uint64_t) in[2]) << 16; case 2: state->padding |= ((uint64_t) in[1]) << 8; case 1: state->padding |= ((uint64_t) in[0]); case 0: break; } } uint64_t siphash24_finalize(struct siphash *state) { uint64_t b; assert(state); b = state->padding | (((uint64_t) state->inlen) << 56); #ifdef DEBUG printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding); #endif state->v3 ^= b; sipround(state); sipround(state); state->v0 ^= b; #ifdef DEBUG printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); #endif state->v2 ^= 0xff; sipround(state); sipround(state); sipround(state); sipround(state); return state->v0 ^ state->v1 ^ state->v2 ^ state->v3; } uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) { struct siphash state; assert(in); assert(k); siphash24_init(&state, k); siphash24_compress(in, inlen, &state); return siphash24_finalize(&state); } systemd-bootchart-233/src/siphash24.h000066400000000000000000000011061315600604400176000ustar00rootroot00000000000000#pragma once #include #include struct siphash { uint64_t v0; uint64_t v1; uint64_t v2; uint64_t v3; uint64_t padding; size_t inlen; }; void siphash24_init(struct siphash *state, const uint8_t k[16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); #define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); systemd-bootchart-233/src/stdio-util.h000066400000000000000000000102041315600604400200670ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include "macro.h" #define xsprintf(buf, fmt, ...) \ assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") #define VA_FORMAT_ADVANCE(format, ap) \ do { \ int _argtypes[128]; \ size_t _i, _k; \ _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ assert(_k < ELEMENTSOF(_argtypes)); \ for (_i = 0; _i < _k; _i++) { \ if (_argtypes[_i] & PA_FLAG_PTR) { \ (void) va_arg(ap, void*); \ continue; \ } \ \ switch (_argtypes[_i]) { \ case PA_INT: \ case PA_INT|PA_FLAG_SHORT: \ case PA_CHAR: \ (void) va_arg(ap, int); \ break; \ case PA_INT|PA_FLAG_LONG: \ (void) va_arg(ap, long int); \ break; \ case PA_INT|PA_FLAG_LONG_LONG: \ (void) va_arg(ap, long long int); \ break; \ case PA_WCHAR: \ (void) va_arg(ap, wchar_t); \ break; \ case PA_WSTRING: \ case PA_STRING: \ case PA_POINTER: \ (void) va_arg(ap, void*); \ break; \ case PA_FLOAT: \ case PA_DOUBLE: \ (void) va_arg(ap, double); \ break; \ case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ (void) va_arg(ap, long double); \ break; \ default: \ assert_not_reached("Unknown format string argument."); \ } \ } \ } while(false) systemd-bootchart-233/src/store.c000066400000000000000000000505271315600604400171350ustar00rootroot00000000000000/*** This file is part of systemd. Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include #include #include #include "alloc-util.h" #include "bootchart.h" #include "cgroup-util.h" #include "def.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "log.h" #include "parse-util.h" #include "store.h" #include "string-util.h" #include "strxcpyx.h" #include "time-util.h" /* * Alloc a static 4k buffer for stdio - primarily used to increase * PSS buffering from the default 1k stdin buffer to reduce * read() overhead. */ static char smaps_buf[4096]; static int skip = 0; double gettime_ns(void) { struct timespec n; clock_gettime(clock_boottime_or_monotonic(), &n); return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); } static char *bufgetline(char *buf) { char *c; if (!buf) return NULL; c = strchr(buf, '\n'); if (c) c++; return c; } static int pid_cmdline_strscpy(int procfd, char *buffer, size_t buf_len, int pid) { char filename[PATH_MAX]; _cleanup_close_ int fd = -1; ssize_t n; sprintf(filename, "%d/cmdline", pid); fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); if (fd < 0) return -errno; n = read(fd, buffer, buf_len-1); if (n > 0) { int i; for (i = 0; i < n; i++) if (buffer[i] == '\0') buffer[i] = ' '; buffer[n] = '\0'; } return 0; } static void garbage_collect_dead_processes(struct ps_struct *ps_first) { struct ps_struct *ps; struct ps_struct *ps_next; ps = ps_first; while ((ps_next = ps->next_running)) { if (!ps_next->still_running) { /* close the stream and fds */ ps_next->schedstat = safe_close(ps_next->schedstat); ps_next->sched = safe_close(ps_next->sched); if (ps_next->smaps) { fclose(ps_next->smaps); ps_next->smaps = NULL; } ps->next_running = ps_next->next_running; } else { ps = ps_next; } /* this resets the flag for both running and dead processes*/ ps_next->still_running = false; } } int log_sample(DIR *proc, int sample, struct ps_struct *ps_first, struct list_sample_data **ptr, int *pscount, int *cpus) { static int vmstat = -1; _cleanup_free_ char *buf_schedstat = NULL; char buf[4096]; char key[256]; char val[256]; char rt[256]; char wt[256]; char *m; int r; int c; int p; int mod; static int e_fd = -1; ssize_t s; ssize_t n; struct dirent *ent; int fd; struct list_sample_data *sampledata; struct ps_sched_struct *ps_prev = NULL; int procfd; int taskfd = -1; sampledata = *ptr; procfd = dirfd(proc); if (procfd < 0) return -errno; if (vmstat < 0) { /* block stuff */ vmstat = openat(procfd, "vmstat", O_RDONLY|O_CLOEXEC); if (vmstat < 0) return log_error_errno(errno, "Failed to open /proc/vmstat: %m"); } n = pread(vmstat, buf, sizeof(buf) - 1, 0); if (n <= 0) { vmstat = safe_close(vmstat); if (n < 0) return -errno; return -ENODATA; } buf[n] = '\0'; m = buf; while (m) { if (sscanf(m, "%s %s", key, val) < 2) goto vmstat_next; if (streq(key, "pgpgin")) sampledata->blockstat.bi = atoi(val); if (streq(key, "pgpgout")) { sampledata->blockstat.bo = atoi(val); break; } vmstat_next: m = bufgetline(m); if (!m) break; } /* Parse "/proc/schedstat" for overall CPU utilization */ r = read_full_file("/proc/schedstat", &buf_schedstat, NULL); if (r < 0) return log_error_errno(r, "Unable to read schedstat: %m"); m = buf_schedstat; while (m) { if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3) goto schedstat_next; if (strstr(key, "cpu")) { r = safe_atoi((const char*)(key+3), &c); if (r < 0 || c > MAXCPUS -1) /* Oops, we only have room for MAXCPUS data */ break; sampledata->runtime[c] = atoll(rt); sampledata->waittime[c] = atoll(wt); if (c == *cpus) *cpus = c + 1; } schedstat_next: m = bufgetline(m); if (!m) break; } if (arg_entropy) { if (e_fd < 0) { e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY|O_CLOEXEC); if (e_fd < 0) return log_error_errno(errno, "Failed to open /proc/sys/kernel/random/entropy_avail: %m"); } n = pread(e_fd, buf, sizeof(buf) - 1, 0); if (n <= 0) { e_fd = safe_close(e_fd); } else { buf[n] = '\0'; sampledata->entropy_avail = atoi(buf); } } while ((ent = readdir(proc)) != NULL) { char filename[PATH_MAX]; int pid; struct ps_struct *ps; if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) continue; pid = atoi(ent->d_name); if (pid >= MAXPIDS) continue; ps = ps_first; while (ps->next_running) { ps = ps->next_running; if (ps->pid == pid) break; } /* end of our LL? then append a new record */ if (ps->pid != pid) { _cleanup_fclose_ FILE *st = NULL; char t[32]; struct ps_struct *parent; /* find the insertion point for the last item */ struct ps_struct **ps_next = &ps->next_ps; while (*ps_next) { ps_next = &(*ps_next)->next_ps; } assert(!*ps_next); assert(!ps->next_running); *ps_next = ps->next_running = new0(struct ps_struct, 1); if (!*ps_next) return log_oom(); ps = *ps_next; ps->pid = pid; ps->sched = -1; ps->schedstat = -1; ps->sample = new0(struct ps_sched_struct, 1); if (!ps->sample) return log_oom(); ps->sample->sampledata = sampledata; (*pscount)++; /* mark our first sample */ ps->first = ps->last = ps->sample; /* get name, start time; requires CONFIG_SCHED_DEBUG in kernel */ if (ps->sched < 0) { sprintf(filename, "%d/sched", pid); ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC); if (ps->sched < 0) goto no_sched; } s = pread(ps->sched, buf, sizeof(buf) - 1, 0); if (s <= 0) { ps->sched = safe_close(ps->sched); goto no_sched; } buf[s] = '\0'; if (!sscanf(buf, "%s %*s %*s", key)) goto no_sched; strscpy(ps->name, sizeof(ps->name), key); /* discard line 2 */ m = bufgetline(buf); if (!m) goto no_sched; m = bufgetline(m); if (!m) goto no_sched; if (!sscanf(m, "%*s %*s %s", t)) goto no_sched; r = safe_atod(t, &ps->starttime); if (r < 0) goto no_sched; ps->starttime /= 1000.0; no_sched: /* cmdline */ if (arg_show_cmdline) pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid); if (arg_show_cgroup) /* if this fails, that's OK */ cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, ps->pid, &ps->cgroup); /* ppid */ sprintf(filename, "%d/stat", pid); fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); if (fd < 0) continue; st = fdopen(fd, "re"); if (!st) { close(fd); continue; } if (!fscanf(st, "%*s %*s %*s %i", &p)) continue; ps->ppid = p; /* * setup child pointers * * these are used to paint the tree coherently later * each parent has a LL of children, and a LL of siblings */ if (pid == 1) continue; /* nothing to do for init atm */ /* kthreadd has ppid=0, which breaks our tree ordering */ if (ps->ppid == 0) ps->ppid = 1; parent = ps_first; while ((parent->next_ps && parent->pid != ps->ppid)) parent = parent->next_ps; if (parent->pid != ps->ppid) { /* orphan */ ps->ppid = 1; parent = ps_first->next_ps; } ps->parent = parent; /* * append ourselves to the list of children * TODO: consider if prepending is OK for efficiency here. */ { struct ps_struct **children = &parent->children; while (*children) children = &(*children)->next; *children = ps; } } /* else -> found pid, append data in ps */ /* below here is all continuous logging parts - we get here on every * iteration */ /* rt, wt */ if (ps->schedstat < 0) { sprintf(filename, "%d/schedstat", pid); ps->schedstat = openat(procfd, filename, O_RDONLY|O_CLOEXEC); if (ps->schedstat < 0) continue; } s = pread(ps->schedstat, buf, sizeof(buf) - 1, 0); if (s <= 0) continue; buf[s] = '\0'; if (!sscanf(buf, "%s %s %*s", rt, wt)) continue; ps->sample->next = new0(struct ps_sched_struct, 1); if (!ps->sample->next) return log_oom(); ps->sample->next->prev = ps->sample; ps->sample = ps->sample->next; ps->last = ps->sample; ps->sample->runtime = atoll(rt); ps->sample->waittime = atoll(wt); ps->sample->sampledata = sampledata; ps->sample->ps_new = ps; if (ps_prev) ps_prev->cross = ps->sample; ps_prev = ps->sample; ps->total = (ps->last->runtime - ps->first->runtime) / 1000000000.0; /* Take into account CPU runtime/waittime spent in non-main threads of the process * by parsing "/proc/[pid]/task/[tid]/schedstat" for all [tid] != [pid] * See https://github.com/systemd/systemd/issues/139 */ /* Browse directory "/proc/[pid]/task" to know the thread ids of process [pid] */ snprintf(filename, sizeof(filename), PID_FMT "/task", pid); taskfd = openat(procfd, filename, O_RDONLY|O_DIRECTORY|O_CLOEXEC); if (taskfd >= 0) { _cleanup_closedir_ DIR *taskdir = NULL; taskdir = fdopendir(taskfd); if (!taskdir) { safe_close(taskfd); return -errno; } FOREACH_DIRENT(ent, taskdir, break) { int tid = -1; _cleanup_close_ int tid_schedstat = -1; long long delta_rt; long long delta_wt; if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) continue; /* Skip main thread as it was already accounted */ r = safe_atoi(ent->d_name, &tid); if (r < 0 || tid == pid) continue; /* Parse "/proc/[pid]/task/[tid]/schedstat" */ snprintf(filename, sizeof(filename), PID_FMT "/schedstat", tid); tid_schedstat = openat(taskfd, filename, O_RDONLY|O_CLOEXEC); if (tid_schedstat == -1) continue; s = pread(tid_schedstat, buf, sizeof(buf) - 1, 0); if (s <= 0) continue; buf[s] = '\0'; if (!sscanf(buf, "%s %s %*s", rt, wt)) continue; r = safe_atolli(rt, &delta_rt); if (r < 0) continue; r = safe_atolli(rt, &delta_wt); if (r < 0) continue; ps->sample->runtime += delta_rt; ps->sample->waittime += delta_wt; } } if (!arg_pss) goto catch_rename; /* Pss */ if (!ps->smaps) { sprintf(filename, "%d/smaps", pid); fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); if (fd < 0) continue; ps->smaps = fdopen(fd, "re"); if (!ps->smaps) { close(fd); continue; } setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); } else { rewind(ps->smaps); } /* test to see if we need to skip another field */ if (skip == 0) { if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { continue; } if (fread(buf, 1, 28 * 15, ps->smaps) != (28 * 15)) { continue; } if (buf[392] == 'V') { skip = 2; } else { skip = 1; } rewind(ps->smaps); } while (1) { int pss_kb; /* skip one line, this contains the object mapped. */ if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { break; } /* then there's a 28 char 14 line block */ if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) { break; } pss_kb = atoi(&buf[61]); ps->sample->pss += pss_kb; /* skip one more line if this is a newer kernel */ if (skip == 2) { if (fgets(buf, sizeof(buf), ps->smaps) == NULL) break; } } if (ps->sample->pss > ps->pss_max) ps->pss_max = ps->sample->pss; catch_rename: /* catch process rename, try to randomize time */ mod = (arg_hz < 4.0) ? 4.0 : (arg_hz / 4.0); if (((sample - ps->pid) + pid) % (int)(mod) == 0) { /* re-fetch name */ /* get name, start time */ if (ps->sched < 0) { sprintf(filename, "%d/sched", pid); ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC); if (ps->sched < 0) goto no_sched2; } s = pread(ps->sched, buf, sizeof(buf) - 1, 0); if (s <= 0) continue; buf[s] = '\0'; if (!sscanf(buf, "%s %*s %*s", key)) continue; strscpy(ps->name, sizeof(ps->name), key); no_sched2: /* cmdline */ if (arg_show_cmdline) pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid); } ps->still_running = true; } garbage_collect_dead_processes(ps_first); return 0; } systemd-bootchart-233/src/store.h000066400000000000000000000020741315600604400171340ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include "bootchart.h" double gettime_ns(void); void log_uptime(void); int log_sample(DIR *proc, int sample, struct ps_struct *ps_first, struct list_sample_data **ptr, int *pscount, int *cpus); systemd-bootchart-233/src/string-util.c000066400000000000000000000234761315600604400202650ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "alloc-util.h" #include "macro.h" #include "string-util.h" #include "util.h" int strcmp_ptr(const char *a, const char *b) { /* Like strcmp(), but tries to make sense of NULL pointers */ if (a && b) return strcmp(a, b); if (!a && b) return -1; if (a && !b) return 1; return 0; } char* endswith(const char *s, const char *postfix) { size_t sl, pl; assert(s); assert(postfix); sl = strlen(s); pl = strlen(postfix); if (pl == 0) return (char*) s + sl; if (sl < pl) return NULL; if (memcmp(s + sl - pl, postfix, pl) != 0) return NULL; return (char*) s + sl - pl; } static size_t strcspn_escaped(const char *s, const char *reject) { bool escaped = false; int n; for (n=0; s[n]; n++) { if (escaped) escaped = false; else if (s[n] == '\\') escaped = true; else if (strchr(reject, s[n])) break; } /* if s ends in \, return index of previous char */ return n - escaped; } /* Split a string into words. */ const char* split(const char **state, size_t *l, const char *separator, bool quoted) { const char *current; current = *state; if (!*current) { assert(**state == '\0'); return NULL; } current += strspn(current, separator); if (!*current) { *state = current; return NULL; } if (quoted && strchr("\'\"", *current)) { char quotechars[2] = {*current, '\0'}; *l = strcspn_escaped(current + 1, quotechars); if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || (current[*l + 2] && !strchr(separator, current[*l + 2]))) { /* right quote missing or garbage at the end */ *state = current; return NULL; } *state = current++ + *l + 2; } else if (quoted) { *l = strcspn_escaped(current, separator); if (current[*l] && !strchr(separator, current[*l])) { /* unfinished escape */ *state = current; return NULL; } *state = current + *l; } else { *l = strcspn(current, separator); *state = current + *l; } return current; } char *strnappend(const char *s, const char *suffix, size_t b) { size_t a; char *r; if (!s && !suffix) return strdup(""); if (!s) return strndup(suffix, b); if (!suffix) return strdup(s); assert(s); assert(suffix); a = strlen(s); if (b > ((size_t) -1) - a) return NULL; r = new(char, a+b+1); if (!r) return NULL; memcpy(r, s, a); memcpy(r+a, suffix, b); r[a+b] = 0; return r; } char *strappend(const char *s, const char *suffix) { return strnappend(s, suffix, suffix ? strlen(suffix) : 0); } char *strjoin(const char *x, ...) { va_list ap; size_t l; char *r, *p; va_start(ap, x); if (x) { l = strlen(x); for (;;) { const char *t; size_t n; t = va_arg(ap, const char *); if (!t) break; n = strlen(t); if (n > ((size_t) -1) - l) { va_end(ap); return NULL; } l += n; } } else l = 0; va_end(ap); r = new(char, l+1); if (!r) return NULL; if (x) { p = stpcpy(r, x); va_start(ap, x); for (;;) { const char *t; t = va_arg(ap, const char *); if (!t) break; p = stpcpy(p, t); } va_end(ap); } else r[0] = 0; return r; } char *strstrip(char *s) { char *e; /* Drops trailing whitespace. Modifies the string in * place. Returns pointer to first non-space character */ s += strspn(s, WHITESPACE); for (e = strchr(s, 0); e > s; e --) if (!strchr(WHITESPACE, e[-1])) break; *e = 0; return s; } char *truncate_nl(char *s) { assert(s); s[strcspn(s, NEWLINE)] = 0; return s; } bool nulstr_contains(const char*nulstr, const char *needle) { const char *i; if (!nulstr) return false; NULSTR_FOREACH(i, nulstr) if (streq(i, needle)) return true; return false; } char* strshorten(char *s, size_t l) { assert(s); if (l < strlen(s)) s[l] = 0; return s; } char *strip_tab_ansi(char **ibuf, size_t *_isz) { const char *i, *begin = NULL; enum { STATE_OTHER, STATE_ESCAPE, STATE_BRACKET } state = STATE_OTHER; char *obuf = NULL; size_t osz = 0, isz; FILE *f; assert(ibuf); assert(*ibuf); /* Strips ANSI color and replaces TABs by 8 spaces */ isz = _isz ? *_isz : strlen(*ibuf); f = open_memstream(&obuf, &osz); if (!f) return NULL; for (i = *ibuf; i < *ibuf + isz + 1; i++) { switch (state) { case STATE_OTHER: if (i >= *ibuf + isz) /* EOT */ break; else if (*i == '\x1B') state = STATE_ESCAPE; else if (*i == '\t') fputs(" ", f); else fputc(*i, f); break; case STATE_ESCAPE: if (i >= *ibuf + isz) { /* EOT */ fputc('\x1B', f); break; } else if (*i == '[') { state = STATE_BRACKET; begin = i + 1; } else { fputc('\x1B', f); fputc(*i, f); state = STATE_OTHER; } break; case STATE_BRACKET: if (i >= *ibuf + isz || /* EOT */ (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { fputc('\x1B', f); fputc('[', f); state = STATE_OTHER; i = begin-1; } else if (*i == 'm') state = STATE_OTHER; break; } } if (ferror(f)) { fclose(f); free(obuf); return NULL; } fclose(f); free(*ibuf); *ibuf = obuf; if (_isz) *_isz = osz; return obuf; } char *strextend(char **x, ...) { va_list ap; size_t f, l; char *r, *p; assert(x); l = f = *x ? strlen(*x) : 0; va_start(ap, x); for (;;) { const char *t; size_t n; t = va_arg(ap, const char *); if (!t) break; n = strlen(t); if (n > ((size_t) -1) - l) { va_end(ap); return NULL; } l += n; } va_end(ap); r = realloc(*x, l+1); if (!r) return NULL; p = r + f; va_start(ap, x); for (;;) { const char *t; t = va_arg(ap, const char *); if (!t) break; p = stpcpy(p, t); } va_end(ap); *p = 0; *x = r; return r + l; } char *strrep(const char *s, unsigned n) { size_t l; char *r, *p; unsigned i; assert(s); l = strlen(s); p = r = malloc(l * n + 1); if (!r) return NULL; for (i = 0; i < n; i++) p = stpcpy(p, s); *p = 0; return r; } systemd-bootchart-233/src/string-util.h000066400000000000000000000126161315600604400202640ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include "attributes.h" #include "macro.h" /* What is interpreted as whitespace? */ #define WHITESPACE " \t\n\r" #define NEWLINE "\n\r" #define QUOTES "\"\'" #define COMMENTS "#;" #define GLOB_CHARS "*?[" #define DIGITS "0123456789" #define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS #define ALPHANUMERICAL LETTERS DIGITS #define streq(a,b) (strcmp((a),(b)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) #define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) int strcmp_ptr(const char *a, const char *b) _pure_; static inline bool streq_ptr(const char *a, const char *b) { return strcmp_ptr(a, b) == 0; } static inline const char* strempty(const char *s) { return s ? s : ""; } static inline const char* strnull(const char *s) { return s ? s : "(null)"; } static inline const char *strna(const char *s) { return s ? s : "n/a"; } static inline bool isempty(const char *p) { return !p || !p[0]; } static inline char *startswith(const char *s, const char *prefix) { size_t l; l = strlen(prefix); if (strncmp(s, prefix, l) == 0) return (char*) s + l; return NULL; } static inline char *startswith_no_case(const char *s, const char *prefix) { size_t l; l = strlen(prefix); if (strncasecmp(s, prefix, l) == 0) return (char*) s + l; return NULL; } char *endswith(const char *s, const char *postfix) _pure_; const char* split(const char **state, size_t *l, const char *separator, bool quoted); #define FOREACH_WORD(word, length, s, state) \ _FOREACH_WORD(word, length, s, WHITESPACE, false, state) #define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ _FOREACH_WORD(word, length, s, separator, false, state) #define FOREACH_WORD_QUOTED(word, length, s, state) \ _FOREACH_WORD(word, length, s, WHITESPACE, true, state) #define _FOREACH_WORD(word, length, s, separator, quoted, state) \ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) char *strappend(const char *s, const char *suffix); char *strnappend(const char *s, const char *suffix, size_t length); char *strjoin(const char *x, ...) _sentinel_; #define strjoina(a, ...) \ ({ \ const char *_appendees_[] = { a, __VA_ARGS__ }; \ char *_d_, *_p_; \ int _len_ = 0; \ unsigned _i_; \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _len_ += strlen(_appendees_[_i_]); \ _p_ = _d_ = alloca(_len_ + 1); \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _p_ = stpcpy(_p_, _appendees_[_i_]); \ *_p_ = 0; \ _d_; \ }) char *strstrip(char *s); char *truncate_nl(char *s); static inline bool _pure_ in_charset(const char *s, const char* charset) { assert(s); assert(charset); return s[strspn(s, charset)] == '\0'; } char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent); char *ellipsize(const char *s, size_t length, unsigned percent); bool nulstr_contains(const char*nulstr, const char *needle); char* strshorten(char *s, size_t l); char *strip_tab_ansi(char **p, size_t *l); char *strextend(char **x, ...) _sentinel_; char *strrep(const char *s, unsigned n); /* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { if (needlelen <= 0) return (void*) haystack; if (haystacklen < needlelen) return NULL; assert(haystack); assert(needle); return memmem(haystack, haystacklen, needle, needlelen); } systemd-bootchart-233/src/strv.c000066400000000000000000000332101315600604400167650ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include "alloc-util.h" #include "string-util.h" #include "strv.h" #include "util.h" char *strv_find(char **l, const char *name) { char **i; assert(name); STRV_FOREACH(i, l) if (streq(*i, name)) return *i; return NULL; } char *strv_find_prefix(char **l, const char *name) { char **i; assert(name); STRV_FOREACH(i, l) if (startswith(*i, name)) return *i; return NULL; } char *strv_find_startswith(char **l, const char *name) { char **i, *e; assert(name); /* Like strv_find_prefix, but actually returns only the * suffix, not the whole item */ STRV_FOREACH(i, l) { e = startswith(*i, name); if (e) return e; } return NULL; } void strv_clear(char **l) { char **k; if (!l) return; for (k = l; *k; k++) free(*k); *l = NULL; } char **strv_free(char **l) { strv_clear(l); free(l); return NULL; } char **strv_copy(char * const *l) { char **r, **k; k = r = new(char*, strv_length(l) + 1); if (!r) return NULL; if (l) for (; *l; k++, l++) { *k = strdup(*l); if (!*k) { strv_free(r); return NULL; } } *k = NULL; return r; } unsigned strv_length(char * const *l) { unsigned n = 0; if (!l) return 0; for (; *l; l++) n++; return n; } char **strv_new_ap(const char *x, va_list ap) { const char *s; char **a; unsigned n = 0, i = 0; va_list aq; /* As a special trick we ignore all listed strings that equal * (const char*) -1. This is supposed to be used with the * STRV_IFNOTNULL() macro to include possibly NULL strings in * the string list. */ if (x) { n = x == (const char*) -1 ? 0 : 1; va_copy(aq, ap); while ((s = va_arg(aq, const char*))) { if (s == (const char*) -1) continue; n++; } va_end(aq); } a = new(char*, n+1); if (!a) return NULL; if (x) { if (x != (const char*) -1) { a[i] = strdup(x); if (!a[i]) goto fail; i++; } while ((s = va_arg(ap, const char*))) { if (s == (const char*) -1) continue; a[i] = strdup(s); if (!a[i]) goto fail; i++; } } a[i] = NULL; return a; fail: strv_free(a); return NULL; } char **strv_new(const char *x, ...) { char **r; va_list ap; va_start(ap, x); r = strv_new_ap(x, ap); va_end(ap); return r; } int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { char **s, **t; size_t p, q, i = 0, j; assert(a); if (strv_isempty(b)) return 0; p = strv_length(*a); q = strv_length(b); t = realloc(*a, sizeof(char*) * (p + q + 1)); if (!t) return -ENOMEM; t[p] = NULL; *a = t; STRV_FOREACH(s, b) { if (filter_duplicates && strv_contains(t, *s)) continue; t[p+i] = strdup(*s); if (!t[p+i]) goto rollback; i++; t[p+i] = NULL; } assert(i <= q); return (int) i; rollback: for (j = 0; j < i; j++) free(t[p + j]); t[p] = NULL; return -ENOMEM; } int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { int r; char **s; STRV_FOREACH(s, b) { char *v; v = strappend(*s, suffix); if (!v) return -ENOMEM; r = strv_push(a, v); if (r < 0) { free(v); return r; } } return 0; } char **strv_split(const char *s, const char *separator) { const char *word, *state; size_t l; unsigned n, i; char **r; assert(s); n = 0; FOREACH_WORD_SEPARATOR(word, l, s, separator, state) n++; r = new(char*, n+1); if (!r) return NULL; i = 0; FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { r[i] = strndup(word, l); if (!r[i]) { strv_free(r); return NULL; } i++; } r[i] = NULL; return r; } char *strv_join(char **l, const char *separator) { char *r, *e; char **s; size_t n, k; if (!separator) separator = " "; k = strlen(separator); n = 0; STRV_FOREACH(s, l) { if (s != l) n += k; n += strlen(*s); } r = new(char, n+1); if (!r) return NULL; e = r; STRV_FOREACH(s, l) { if (s != l) e = stpcpy(e, separator); e = stpcpy(e, *s); } *e = 0; return r; } int strv_push(char ***l, char *value) { char **c; unsigned n, m; if (!value) return 0; n = strv_length(*l); /* Increase and check for overflow */ m = n + 2; if (m < n) return -ENOMEM; c = realloc_multiply(*l, sizeof(char*), m); if (!c) return -ENOMEM; c[n] = value; c[n+1] = NULL; *l = c; return 0; } int strv_push_pair(char ***l, char *a, char *b) { char **c; unsigned n, m; if (!a && !b) return 0; n = strv_length(*l); /* increase and check for overflow */ m = n + !!a + !!b + 1; if (m < n) return -ENOMEM; c = realloc_multiply(*l, sizeof(char*), m); if (!c) return -ENOMEM; if (a) c[n++] = a; if (b) c[n++] = b; c[n] = NULL; *l = c; return 0; } int strv_push_prepend(char ***l, char *value) { char **c; unsigned n, m, i; if (!value) return 0; n = strv_length(*l); /* increase and check for overflow */ m = n + 2; if (m < n) return -ENOMEM; c = new(char*, m); if (!c) return -ENOMEM; for (i = 0; i < n; i++) c[i+1] = (*l)[i]; c[0] = value; c[n+1] = NULL; free(*l); *l = c; return 0; } int strv_consume(char ***l, char *value) { int r; r = strv_push(l, value); if (r < 0) free(value); return r; } int strv_consume_prepend(char ***l, char *value) { int r; r = strv_push_prepend(l, value); if (r < 0) free(value); return r; } int strv_extend(char ***l, const char *value) { char *v; if (!value) return 0; v = strdup(value); if (!v) return -ENOMEM; return strv_consume(l, v); } char **strv_uniq(char **l) { char **i; /* Drops duplicate entries. The first identical string will be * kept, the others dropped */ STRV_FOREACH(i, l) strv_remove(i+1, *i); return l; } bool strv_is_uniq(char **l) { char **i; STRV_FOREACH(i, l) if (strv_find(i+1, *i)) return false; return true; } char **strv_remove(char **l, const char *s) { char **f, **t; if (!l) return NULL; assert(s); /* Drops every occurrence of s in the string list, edits * in-place. */ for (f = t = l; *f; f++) if (streq(*f, s)) free(*f); else *(t++) = *f; *t = NULL; return l; } char **strv_parse_nulstr(const char *s, size_t l) { const char *p; unsigned c = 0, i = 0; char **v; assert(s || l <= 0); if (l <= 0) return new0(char*, 1); for (p = s; p < s + l; p++) if (*p == 0) c++; if (s[l-1] != 0) c++; v = new0(char*, c+1); if (!v) return NULL; p = s; while (p < s + l) { const char *e; e = memchr(p, 0, s + l - p); v[i] = strndup(p, e ? e - p : s + l - p); if (!v[i]) { strv_free(v); return NULL; } i++; if (!e) break; p = e + 1; } assert(i == c); return v; } char **strv_split_nulstr(const char *s) { const char *i; char **r = NULL; NULSTR_FOREACH(i, s) if (strv_extend(&r, i) < 0) { strv_free(r); return NULL; } if (!r) return strv_new(NULL, NULL); return r; } bool strv_overlap(char **a, char **b) { char **i; STRV_FOREACH(i, a) if (strv_contains(b, *i)) return true; return false; } static int str_compare(const void *_a, const void *_b) { const char **a = (const char**) _a, **b = (const char**) _b; return strcmp(*a, *b); } char **strv_sort(char **l) { if (strv_isempty(l)) return l; qsort(l, strv_length(l), sizeof(char*), str_compare); return l; } bool strv_equal(char **a, char **b) { if (strv_isempty(a)) return strv_isempty(b); if (strv_isempty(b)) return false; for ( ; *a || *b; ++a, ++b) if (!streq_ptr(*a, *b)) return false; return true; } void strv_print(char **l) { char **s; STRV_FOREACH(s, l) puts(*s); } int strv_extendf(char ***l, const char *format, ...) { va_list ap; char *x; int r; va_start(ap, format); r = vasprintf(&x, format, ap); va_end(ap); if (r < 0) return -ENOMEM; return strv_consume(l, x); } char **strv_reverse(char **l) { unsigned n, i; n = strv_length(l); if (n <= 1) return l; for (i = 0; i < n / 2; i++) { char *t; t = l[i]; l[i] = l[n-1-i]; l[n-1-i] = t; } return l; } bool strv_fnmatch(char* const* patterns, const char *s, int flags) { char* const* p; STRV_FOREACH(p, patterns) if (fnmatch(*p, s, 0) == 0) return true; return false; } char ***strv_free_free(char ***l) { char ***i; if (!l) return NULL; for (i = l; *i; i++) strv_free(*i); free(l); return NULL; } char **strv_skip(char **l, size_t n) { while (n > 0) { if (strv_isempty(l)) return l; l++, n--; } return l; } int strv_extend_n(char ***l, const char *value, size_t n) { size_t i, j, k; char **nl; assert(l); if (!value) return 0; if (n == 0) return 0; /* Adds the value value n times to l */ k = strv_length(*l); nl = realloc(*l, sizeof(char*) * (k + n + 1)); if (!nl) return -ENOMEM; *l = nl; for (i = k; i < k + n; i++) { nl[i] = strdup(value); if (!nl[i]) goto rollback; } nl[i] = NULL; return 0; rollback: for (j = k; j < i; j++) free(nl[j]); nl[k] = NULL; return -ENOMEM; } systemd-bootchart-233/src/strv.h000066400000000000000000000136151315600604400170010ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "alloc-util.h" #include "attributes.h" #include "macro.h" char *strv_find(char **l, const char *name) _pure_; char *strv_find_prefix(char **l, const char *name) _pure_; char *strv_find_startswith(char **l, const char *name) _pure_; char **strv_free(char **l); DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); #define _cleanup_strv_free_ _cleanup_(strv_freep) void strv_clear(char **l); char **strv_copy(char * const *l); unsigned strv_length(char * const *l) _pure_; int strv_extend_strv(char ***a, char **b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char **b, const char *suffix); int strv_extend(char ***l, const char *value); int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_push(char ***l, char *value); int strv_push_pair(char ***l, char *a, char *b); int strv_push_prepend(char ***l, char *value); int strv_consume(char ***l, char *value); int strv_consume_prepend(char ***l, char *value); char **strv_remove(char **l, const char *s); char **strv_uniq(char **l); bool strv_is_uniq(char **l); bool strv_equal(char **a, char **b); #define strv_contains(l, s) (!!strv_find((l), (s))) char **strv_new(const char *x, ...) _sentinel_; char **strv_new_ap(const char *x, va_list ap); static inline const char* STRV_IFNOTNULL(const char *x) { return x ? x : (const char *) -1; } static inline bool strv_isempty(char * const *l) { return !l || !*l; } char **strv_split(const char *s, const char *separator); char *strv_join(char **l, const char *separator); char **strv_parse_nulstr(const char *s, size_t l); char **strv_split_nulstr(const char *s); bool strv_overlap(char **a, char **b) _pure_; #define STRV_FOREACH(s, l) \ for ((s) = (l); (s) && *(s); (s)++) #define STRV_FOREACH_BACKWARDS(s, l) \ STRV_FOREACH(s, l) \ ; \ for ((s)--; (l) && ((s) >= (l)); (s)--) #define STRV_FOREACH_PAIR(x, y, l) \ for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) char **strv_sort(char **l); void strv_print(char **l); #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) #define STRV_MAKE_EMPTY ((char*[1]) { NULL }) #define strv_from_stdarg_alloca(first) \ ({ \ char **_l; \ \ if (!first) \ _l = (char**) &first; \ else { \ unsigned _n; \ va_list _ap; \ \ _n = 1; \ va_start(_ap, first); \ while (va_arg(_ap, char*)) \ _n++; \ va_end(_ap); \ \ _l = newa(char*, _n+1); \ _l[_n = 0] = (char*) first; \ va_start(_ap, first); \ for (;;) { \ _l[++_n] = va_arg(_ap, char*); \ if (!_l[_n]) \ break; \ } \ va_end(_ap); \ } \ _l; \ }) #define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) #define FOREACH_STRING(x, ...) \ for (char **_l = ({ \ char **_ll = STRV_MAKE(__VA_ARGS__); \ x = _ll ? _ll[0] : NULL; \ _ll; \ }); \ _l && *_l; \ x = ({ \ _l ++; \ _l[0]; \ })) char **strv_reverse(char **l); bool strv_fnmatch(char* const* patterns, const char *s, int flags); static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) { assert(s); return strv_isempty(patterns) || strv_fnmatch(patterns, s, flags); } char ***strv_free_free(char ***l); char **strv_skip(char **l, size_t n); int strv_extend_n(char ***l, const char *value, size_t n); systemd-bootchart-233/src/strxcpyx.c000066400000000000000000000030531315600604400176750ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2013 Kay Sievers systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ /* * Concatenates/copies strings. In any case, terminates in all cases * with '\0' * and moves the @dest pointer forward to the added '\0'. * Returns the * remaining size, and 0 if the string was truncated. */ #include #include "strxcpyx.h" size_t strpcpy(char **dest, size_t size, const char *src) { size_t len; len = strlen(src); if (len >= size) { if (size > 1) *dest = mempcpy(*dest, src, size-1); size = 0; } else { if (len > 0) { *dest = mempcpy(*dest, src, len); size -= len; } } *dest[0] = '\0'; return size; } size_t strscpy(char *dest, size_t size, const char *src) { char *s; s = dest; return strpcpy(&s, size, src); } systemd-bootchart-233/src/strxcpyx.h000066400000000000000000000015411315600604400177020ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2013 Kay Sievers systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include size_t strpcpy(char **dest, size_t size, const char *src); size_t strscpy(char *dest, size_t size, const char *src); systemd-bootchart-233/src/svg.c000066400000000000000000001610541315600604400165760ustar00rootroot00000000000000/*** This file is part of systemd. Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include #include "alloc-util.h" #include "architecture.h" #include "bootchart.h" #include "fd-util.h" #include "fileio.h" #include "list.h" #include "log.h" #include "macro.h" #include "stdio-util.h" #include "svg.h" #include "utf8.h" #define time_to_graph(t) ((t) * arg_scale_x) #define ps_to_graph(n) ((n) * arg_scale_y) #define kb_to_graph(m) ((m) * arg_scale_y * 0.0001) #define to_color(n) (192.0 - ((n) * 192.0)) #define to_ms(n) (1000.0 * n) static const char * const colorwheel[12] = { "rgb(255,32,32)", // red "rgb(32,192,192)", // cyan "rgb(255,128,32)", // orange "rgb(128,32,192)", // blue-violet "rgb(255,255,32)", // yellow "rgb(192,32,128)", // red-violet "rgb(32,255,32)", // green "rgb(255,64,32)", // red-orange "rgb(32,32,255)", // blue "rgb(255,192,32)", // yellow-orange "rgb(192,32,192)", // violet "rgb(32,192,32)" // yellow-green }; static double idletime = -1.0; static int pfiltered = 0; static int pcount = 0; static int kcount = 0; static double psize = 0; static double ksize = 0; static double esize = 0; static struct list_sample_data *sampledata; static struct list_sample_data *prev_sampledata; static void svg_header(FILE *of, struct list_sample_data *head, double graph_start, int n_cpus) { double w; double h; struct list_sample_data *sampledata_last; assert(head); sampledata_last = head; LIST_FOREACH_BEFORE(link, sampledata, head) { sampledata_last = sampledata; } /* min width is about 1600px due to the label */ w = 150.0 + 10.0 + time_to_graph(sampledata_last->sampletime - graph_start) + 500; w = ((w < 1600.0) ? 1600.0 : w); /* height is variable based on pss, psize, ksize */ h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */ + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */ + psize + ksize + esize + ((n_cpus+1) * 15 * arg_scale_y); fprintf(of, "\n"); fprintf(of, "\n"); //fprintf(of, "\n", 1000 + 150 + (pcount * 20)); fprintf(of, "\n\n"); /* write some basic info as a comment, including some help */ fprintf(of, "\n"); fprintf(of, "\n"); fprintf(of, "\n"); fprintf(of, "\n"); fprintf(of, "\n\n"); fprintf(of, "\n", VERSION); fprintf(of, "\n", arg_hz, arg_samples_len); fprintf(of, "\n", arg_scale_x, arg_scale_y); fprintf(of, "\n", arg_relative, arg_filter); fprintf(of, "\n", arg_pss, arg_entropy); fprintf(of, "\n\n", arg_output_path, arg_init_path); /* style sheet */ fprintf(of, "\n \n\n\n"); } static int svg_title(FILE *of, const char *build, int pscount, double log_start, int overrun) { _cleanup_free_ char *cmdline = NULL; _cleanup_free_ char *model = NULL; _cleanup_free_ char *buf = NULL; char date[256] = "Unknown"; const char *cpu; char *c; time_t t; int r; struct utsname uts; r = read_one_line_file("/proc/cmdline", &cmdline); if (r < 0) { log_error_errno(r, "Unable to read cmdline: %m"); return r; } /* extract root fs so we can find disk model name in sysfs */ /* FIXME: this works only in the simple case */ c = strstr(cmdline, "root=/dev/"); if (c) { char rootbdev[4]; char filename[32]; strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1); rootbdev[3] = '\0'; xsprintf(filename, "/sys/block/%s/device/model", rootbdev); r = read_one_line_file(filename, &model); if (r < 0) log_info("Error reading disk model for %s: %m\n", rootbdev); } /* various utsname parameters */ r = uname(&uts); if (r < 0) { log_error("Error getting uname info\n"); return -errno; } /* date */ t = time(NULL); r = strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); assert_se(r > 0); /* CPU type */ r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf); if (r < 0) cpu = "Unknown"; else cpu = buf; fprintf(of, "Bootchart for %s - %s\n", uts.nodename, date); fprintf(of, "System: %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine); fprintf(of, "CPU: %s\n", cpu); if (model) fprintf(of, "Disk: %s\n", model); fprintf(of, "Boot options: %s\n", cmdline); fprintf(of, "Build: %s\n", build); fprintf(of, "Log start time: %.03fs\n", log_start); fprintf(of, "Idle time: "); if (idletime >= 0.0 && idletime <= 1.0) fprintf(of, "%.01fms", to_ms(idletime)); else if (idletime >= 0.0) fprintf(of, "%.03fs", idletime); else fprintf(of, "Not detected"); fprintf(of, "\n"); fprintf(of, "Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered\n", arg_hz, arg_samples_len, overrun, pscount, pfiltered); return 0; } static void svg_graph_box(FILE *of, struct list_sample_data *head, int height, double graph_start) { double d = 0.0; int i = 0; double finalsample = 0.0; struct list_sample_data *sampledata_last; sampledata_last = head; LIST_FOREACH_BEFORE(link, sampledata, head) { sampledata_last = sampledata; } finalsample = sampledata_last->sampletime; /* outside box, fill */ fprintf(of, "\n", time_to_graph(0.0), time_to_graph(finalsample - graph_start), ps_to_graph(height)); for (d = graph_start; d <= finalsample; d += (arg_scale_x < 5.0 ? 10.0 : arg_scale_x < 50.0 ? 1.0 : arg_scale_x < 500.0 ? 0.1 : 0.01)) { /* lines for each second */ if (i % 50 == 0) fprintf(of, " \n", time_to_graph(d - graph_start), time_to_graph(d - graph_start), ps_to_graph(height)); else if (i % 10 == 0) fprintf(of, " \n", time_to_graph(d - graph_start), time_to_graph(d - graph_start), ps_to_graph(height)); else fprintf(of, " \n", time_to_graph(d - graph_start), time_to_graph(d - graph_start), ps_to_graph(height)); /* time label */ if (i % 10 == 0) fprintf(of, " %.01fs\n", time_to_graph(d - graph_start), -5.0, d - graph_start); i++; } } /* xml comments must not contain "--" */ static char* xml_comment_encode(const char* name) { char *enc_name, *p; enc_name = strdup(name); if (!enc_name) return NULL; for (p = enc_name; *p; p++) if (p[0] == '-' && p[1] == '-') p[1] = '_'; return enc_name; } static void svg_pss_graph(FILE *of, struct list_sample_data *head, struct ps_struct *ps_first, double graph_start) { struct ps_struct *ps; int i; struct list_sample_data *sampledata_last; sampledata_last = head; LIST_FOREACH_BEFORE(link, sampledata, head) { sampledata_last = sampledata; } fprintf(of, "\n\n\n"); fprintf(of, "\n Memory allocation - Pss\n"); /* vsize 1000 == 1000mb */ svg_graph_box(of, head, 100, graph_start); /* draw some hlines for usable memory sizes */ for (i = 100000; i < 1000000; i += 100000) { fprintf(of, " \n", time_to_graph(.0), kb_to_graph(i), time_to_graph(sampledata_last->sampletime - graph_start), kb_to_graph(i)); fprintf(of, " %dM\n", time_to_graph(sampledata_last->sampletime - graph_start) + 5, kb_to_graph(i), (1000000 - i) / 1000); } fprintf(of, "\n"); /* now plot the graph itself */ i = 1; prev_sampledata = head; LIST_FOREACH_BEFORE(link, sampledata, head) { int bottom; int top; struct ps_sched_struct *cross_place; bottom = 0; top = 0; /* put all the small pss blocks into the bottom */ ps = ps_first; while (ps->next_ps) { ps = ps->next_ps; if (!ps) continue; ps->sample = ps->first; while (ps->sample->next) { ps->sample = ps->sample->next; if (ps->sample->sampledata == sampledata) break; } if (ps->sample->sampledata == sampledata) { if (ps->sample->pss <= (100 * arg_scale_y)) top += ps->sample->pss; break; } } while (ps->sample->cross) { cross_place = ps->sample->cross; ps = ps->sample->cross->ps_new; ps->sample = cross_place; if (ps->sample->pss <= (100 * arg_scale_y)) top += ps->sample->pss; } fprintf(of, " \n", "rgb(64,64,64)", time_to_graph(prev_sampledata->sampletime - graph_start), kb_to_graph(1000000.0 - top), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), kb_to_graph(top - bottom)); bottom = top; /* now plot the ones that are of significant size */ ps = ps_first; while (ps->next_ps) { ps = ps->next_ps; if (!ps) continue; ps->sample = ps->first; while (ps->sample->next) { ps->sample = ps->sample->next; if (ps->sample->sampledata == sampledata) break; } /* don't draw anything smaller than 2mb */ if (ps->sample->sampledata != sampledata) continue; if (ps->sample->pss > (100 * arg_scale_y)) { top = bottom + ps->sample->pss; fprintf(of, " \n", colorwheel[ps->pid % 12], time_to_graph(prev_sampledata->sampletime - graph_start), kb_to_graph(1000000.0 - top), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), kb_to_graph(top - bottom)); bottom = top; } break; } while ((cross_place = ps->sample->cross)) { ps = ps->sample->cross->ps_new; ps->sample = cross_place; if (ps->sample->pss > (100 * arg_scale_y)) { top = bottom + ps->sample->pss; fprintf(of, " \n", colorwheel[ps->pid % 12], time_to_graph(prev_sampledata->sampletime - graph_start), kb_to_graph(1000000.0 - top), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), kb_to_graph(top - bottom)); bottom = top; } } prev_sampledata = sampledata; i++; } /* overlay all the text labels */ i = 1; LIST_FOREACH_BEFORE(link, sampledata, head) { int bottom; int top = 0; struct ps_sched_struct *prev_sample; struct ps_sched_struct *cross_place; /* put all the small pss blocks into the bottom */ ps = ps_first->next_ps; while (ps->next_ps) { ps = ps->next_ps; if (!ps) continue; ps->sample = ps->first; while (ps->sample->next) { ps->sample = ps->sample->next; if (ps->sample->sampledata == sampledata) break; } if (ps->sample->sampledata == sampledata) { if (ps->sample->pss <= (100 * arg_scale_y)) top += ps->sample->pss; break; } } while ((cross_place = ps->sample->cross)) { ps = ps->sample->cross->ps_new; ps->sample = cross_place; if (ps->sample->pss <= (100 * arg_scale_y)) top += ps->sample->pss; } bottom = top; /* now plot the ones that are of significant size */ ps = ps_first; while (ps->next_ps) { prev_sample = ps->sample; ps = ps->next_ps; if (!ps) continue; ps->sample = ps->first; while (ps->sample->next) { prev_sample = ps->sample; ps->sample = ps->sample->next; if (ps->sample->sampledata == sampledata) break; } /* don't draw anything smaller than 2mb */ if (ps->sample->sampledata == sampledata) { if (ps->sample->pss > (100 * arg_scale_y)) { top = bottom + ps->sample->pss; /* draw a label with the process / PID */ if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) fprintf(of, " %s [%i]\n", time_to_graph(sampledata->sampletime - graph_start), kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), ps->name, ps->pid); bottom = top; } break; } } while ((cross_place = ps->sample->cross)) { ps = ps->sample->cross->ps_new; ps->sample = cross_place; prev_sample = ps->sample->prev; if (ps->sample->pss > (100 * arg_scale_y)) { top = bottom + ps->sample->pss; /* draw a label with the process / PID */ if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) fprintf(of, " %s [%i]\n", time_to_graph(sampledata->sampletime - graph_start), kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), ps->name, ps->pid); bottom = top; } } i++; } /* debug output - full data dump */ fprintf(of, "\n\n\n"); ps = ps_first; while (ps->next_ps) { _cleanup_free_ char *enc_name = NULL; ps = ps->next_ps; if (!ps) continue; enc_name = xml_comment_encode(ps->name); if (!enc_name) continue; fprintf(of, "\n"); } } static void svg_io_bi_bar(FILE *of, struct list_sample_data *head, int n_samples, double graph_start, double interval) { double max = 0.0; double range; int max_here = 0; int i; int k; struct list_sample_data *start_sampledata; struct list_sample_data *stop_sampledata; fprintf(of, "\n"); fprintf(of, "IO utilization - read\n"); /* * calculate rounding range * * We need to round IO data since IO block data is not updated on * each poll. Applying a smoothing function loses some burst data, * so keep the smoothing range short. */ range = 0.25 / (1.0 / arg_hz); if (range < 2.0) range = 2.0; /* no smoothing */ /* surrounding box */ svg_graph_box(of, head, 5, graph_start); /* find the max IO first */ i = 1; LIST_FOREACH_BEFORE(link, sampledata, head) { int start; int stop; int diff; double tot; start = MAX(i - ((range / 2) - 1), 0); stop = MIN(i + (range / 2), n_samples - 1); diff = (stop - start); start_sampledata = sampledata; stop_sampledata = sampledata; for (k = 0; k < ((range/2) - 1) && start_sampledata->link_next; k++) start_sampledata = start_sampledata->link_next; for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) stop_sampledata = stop_sampledata->link_prev; tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff; if (tot > max) { max = tot; max_here = i; } i++; } /* plot bi */ i = 1; prev_sampledata = head; LIST_FOREACH_BEFORE(link, sampledata, head) { int start; int stop; int diff; double tot; double pbi = 0; start = MAX(i - ((range / 2) - 1), 0); stop = MIN(i + (range / 2), n_samples); diff = (stop - start); start_sampledata = sampledata; stop_sampledata = sampledata; for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++) start_sampledata = start_sampledata->link_next; for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) stop_sampledata = stop_sampledata->link_prev; tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff; if (max > 0) pbi = tot / max; if (pbi > 0.001) fprintf(of, "\n", time_to_graph(prev_sampledata->sampletime - graph_start), (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), pbi * (arg_scale_y * 5)); /* labels around highest value */ if (i == max_here) fprintf(of, " %0.2fmb/sec\n", time_to_graph(sampledata->sampletime - graph_start) + 5, ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15, max / 1024.0 / (interval / 1000000000.0)); i++; prev_sampledata = sampledata; } } static void svg_io_bo_bar(FILE *of, struct list_sample_data *head, int n_samples, double graph_start, double interval) { double max = 0.0; double range; int max_here = 0; int i; int k; struct list_sample_data *start_sampledata; struct list_sample_data *stop_sampledata; fprintf(of, "\n"); fprintf(of, "IO utilization - write\n"); /* * calculate rounding range * * We need to round IO data since IO block data is not updated on * each poll. Applying a smoothing function loses some burst data, * so keep the smoothing range short. */ range = 0.25 / (1.0 / arg_hz); if (range < 2.0) range = 2.0; /* no smoothing */ /* surrounding box */ svg_graph_box(of, head, 5, graph_start); /* find the max IO first */ i = 0; LIST_FOREACH_BEFORE(link, sampledata, head) { int start; int stop; int diff; double tot; start = MAX(i - ((range / 2) - 1), 0); stop = MIN(i + (range / 2), n_samples - 1); diff = (stop - start); start_sampledata = sampledata; stop_sampledata = sampledata; for (k = 0; k < (range/2) - 1 && start_sampledata->link_next; k++) start_sampledata = start_sampledata->link_next; for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) stop_sampledata = stop_sampledata->link_prev; tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff; if (tot > max) { max = tot; max_here = i; } i++; } /* plot bo */ prev_sampledata = head; i = 1; LIST_FOREACH_BEFORE(link, sampledata, head) { int start, stop, diff; double tot, pbo; pbo = 0; start = MAX(i - ((range / 2) - 1), 0); stop = MIN(i + (range / 2), n_samples); diff = (stop - start); start_sampledata = sampledata; stop_sampledata = sampledata; for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++) start_sampledata = start_sampledata->link_next; for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) stop_sampledata = stop_sampledata->link_prev; tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff; if (max > 0) pbo = tot / max; if (pbo > 0.001) fprintf(of, "\n", time_to_graph(prev_sampledata->sampletime - graph_start), (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), pbo * (arg_scale_y * 5)); /* labels around highest bo value */ if (i == max_here) fprintf(of, " %0.2fmb/sec\n", time_to_graph(sampledata->sampletime - graph_start) + 5, ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))), max / 1024.0 / (interval / 1000000000.0)); i++; prev_sampledata = sampledata; } } static void svg_cpu_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) { fprintf(of, "\n"); if (cpu_num < 0) fprintf(of, "CPU[overall] utilization\n"); else fprintf(of, "CPU[%d] utilization\n", cpu_num); /* surrounding box */ svg_graph_box(of, head, 5, graph_start); /* bars for each sample, proportional to the CPU util. */ prev_sampledata = head; LIST_FOREACH_BEFORE(link, sampledata, head) { int c; double trt; double ptrt; ptrt = trt = 0.0; if (cpu_num < 0) for (c = 0; c < n_cpus; c++) trt += sampledata->runtime[c] - prev_sampledata->runtime[c]; else trt = sampledata->runtime[cpu_num] - prev_sampledata->runtime[cpu_num]; trt = trt / 1000000000.0; if (cpu_num < 0) trt = trt / (double)n_cpus; if (trt > 0.0) ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime); if (ptrt > 1.0) ptrt = 1.0; if (ptrt > 0.001) fprintf(of, "\n", time_to_graph(prev_sampledata->sampletime - graph_start), (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), ptrt * (arg_scale_y * 5)); prev_sampledata = sampledata; } } static void svg_wait_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) { fprintf(of, "\n"); if (cpu_num < 0) fprintf(of, "CPU[overall] wait\n"); else fprintf(of, "CPU[%d] wait\n", cpu_num); /* surrounding box */ svg_graph_box(of, head, 5, graph_start); /* bars for each sample, proportional to the CPU util. */ prev_sampledata = head; LIST_FOREACH_BEFORE(link, sampledata, head) { int c; double twt; double ptwt; ptwt = twt = 0.0; if (cpu_num < 0) for (c = 0; c < n_cpus; c++) twt += sampledata->waittime[c] - prev_sampledata->waittime[c]; else twt = sampledata->waittime[cpu_num] - prev_sampledata->waittime[cpu_num]; twt = twt / 1000000000.0; if (cpu_num < 0) twt = twt / (double)n_cpus; if (twt > 0.0) ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime); if (ptwt > 1.0) ptwt = 1.0; if (ptwt > 0.001) fprintf(of, "\n", time_to_graph(prev_sampledata->sampletime - graph_start), ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), ptwt * (arg_scale_y * 5)); prev_sampledata = sampledata; } } static void svg_entropy_bar(FILE *of, struct list_sample_data *head, double graph_start) { fprintf(of, "\n"); fprintf(of, "Entropy pool size\n"); /* surrounding box */ svg_graph_box(of, head, 5, graph_start); /* bars for each sample, scale 0-4096 */ prev_sampledata = head; LIST_FOREACH_BEFORE(link, sampledata, head) { fprintf(of, "\n", time_to_graph(prev_sampledata->sampletime - graph_start), ((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))), time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), (sampledata->entropy_avail / 4096.) * (arg_scale_y * 5)); prev_sampledata = sampledata; } } static struct ps_struct *get_next_ps(struct ps_struct *ps, struct ps_struct *ps_first) { /* * walk the list of processes and return the next one to be * painted */ if (ps == ps_first) return ps->next_ps; /* go deep */ if (ps->children) return ps->children; /* find siblings */ if (ps->next) return ps->next; /* go back for parent siblings */ for (;;) { if (ps->parent && ps->parent->next) return ps->parent->next; ps = ps->parent; if (!ps) return ps; } return NULL; } static bool ps_filter(struct ps_struct *ps) { if (!arg_filter) return false; /* can't draw data when there is only 1 sample (need start + stop) */ if (ps->first == ps->last) return true; /* don't filter kthreadd */ if (ps->pid == 2) return false; /* drop stuff that doesn't use any real CPU time */ if (ps->total <= 0.001) return true; return 0; } static void svg_do_initcall(FILE *of, struct list_sample_data *head, int count_only, double graph_start) { _cleanup_pclose_ FILE *f = NULL; double t; char func[256]; int ret; int usecs; /* can't plot initcall when disabled or in relative mode */ if (!arg_initcall || arg_relative) { kcount = 0; return; } if (!count_only) { fprintf(of, "\n"); fprintf(of, "Kernel init threads\n"); /* surrounding box */ svg_graph_box(of, head, kcount, graph_start); } kcount = 0; /* * Initcall graphing - parses dmesg buffer and displays kernel threads * This somewhat uses the same methods and scaling to show processes * but looks a lot simpler. It's overlaid entirely onto the PS graph * when appropriate. */ f = popen("dmesg", "r"); if (!f) return; while (!feof(f)) { int c; int z = 0; char l[256]; char *p; if (fgets(l, sizeof(l) - 1, f) == NULL) continue; if (l[0] == '<' && l[1] && l[2] == '>') p = l + 3; else p = l; c = sscanf(p, "[%lf] initcall %s %*s %d %*s %d %*s", &t, func, &ret, &usecs); if (c != 4) { /* also parse initcalls done by module loading */ c = sscanf(p, "[%lf] initcall %s %*s %*s %d %*s %d %*s", &t, func, &ret, &usecs); if (c != 4) continue; } /* chop the +0xXX/0xXX stuff */ while(func[z] != '+') z++; func[z] = 0; if (count_only) { /* filter out irrelevant stuff */ if (usecs >= 1000) kcount++; continue; } fprintf(of, "\n", func, t, usecs, ret); if (usecs < 1000) continue; /* rect */ fprintf(of, " \n", time_to_graph(t - (usecs / 1000000.0)), ps_to_graph(kcount), time_to_graph(usecs / 1000000.0), ps_to_graph(1)); /* label */ if (usecs > 1000000.0) fprintf(of, " %s %.03fs\n", time_to_graph(t - (usecs / 1000000.0)) + 5, ps_to_graph(kcount) + 15, func, usecs / 1000000.0); else fprintf(of, " %s %.01fms\n", time_to_graph(t - (usecs / 1000000.0)) + 5, ps_to_graph(kcount) + 15, func, usecs / 1000.0); kcount++; } } static void svg_ps_bars(FILE *of, struct list_sample_data *head, int n_samples, int n_cpus, struct ps_struct *ps_first, double graph_start, double interval) { struct ps_struct *ps; int i = 0; int j = 0; int pid; double w = 0.0; fprintf(of, "\n"); fprintf(of, "Processes\n"); /* surrounding box */ svg_graph_box(of, head, pcount, graph_start); /* pass 2 - ps boxes */ ps = ps_first; while ((ps = get_next_ps(ps, ps_first))) { _cleanup_free_ char *enc_name = NULL, *escaped = NULL; double endtime; double starttime; int t; if (!utf8_is_printable(ps->name, strlen(ps->name))) escaped = utf8_escape_non_printable(ps->name); enc_name = xml_comment_encode(escaped ? escaped : ps->name); if (!enc_name) continue; /* leave some trace of what we actually filtered etc. */ fprintf(of, "\n", enc_name, ps->pid, ps->ppid, to_ms(ps->total)); starttime = ps->first->sampledata->sampletime; if (!ps_filter(ps)) { /* remember where _to_ our children need to draw a line */ ps->pos_x = time_to_graph(starttime - graph_start); ps->pos_y = ps_to_graph(j+1); /* bottom left corner */ } else if (ps->parent){ /* hook children to our parent coords instead */ ps->pos_x = ps->parent->pos_x; ps->pos_y = ps->parent->pos_y; /* if this is the last child, we might still need to draw a connecting line */ if ((!ps->next) && (ps->parent)) fprintf(of, " \n", ps->parent->pos_x, ps_to_graph(j-1) + 10.0, /* whee, use the last value here */ ps->parent->pos_x, ps->parent->pos_y); continue; } else { continue; } endtime = ps->last->sampledata->sampletime; fprintf(of, " \n", time_to_graph(starttime - graph_start), ps_to_graph(j), time_to_graph(ps->last->sampledata->sampletime - starttime), ps_to_graph(1)); /* paint cpu load over these */ ps->sample = ps->first; t = 1; while (ps->sample->next) { double rt, prt; double wt, wrt; struct ps_sched_struct *prev; prev = ps->sample; ps->sample = ps->sample->next; /* calculate over interval */ rt = ps->sample->runtime - prev->runtime; wt = ps->sample->waittime - prev->waittime; prt = (rt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); wrt = (wt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); /* this can happen if timekeeping isn't accurate enough */ if (prt > 1.0) prt = 1.0; if (wrt > 1.0) wrt = 1.0; if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */ continue; fprintf(of, " \n", time_to_graph(prev->sampledata->sampletime - graph_start), ps_to_graph(j), time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime), ps_to_graph(wrt)); /* draw cpu over wait - TODO figure out how/why run + wait > interval */ fprintf(of, " \n", time_to_graph(prev->sampledata->sampletime - graph_start), ps_to_graph(j + (1.0 - prt)), time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime), ps_to_graph(prt)); t++; } /* determine where to display the process name */ if ((endtime - starttime) < 1.5) /* too small to fit label inside the box */ w = endtime; else w = starttime; /* text label of process name */ if ((ps->last->runtime - ps->first->runtime) > 1000000000.0) fprintf(of, " %s [%i]%.03fs %s\n", time_to_graph(w - graph_start) + 5.0, ps_to_graph(j) + 14.0, escaped ? escaped : ps->name, ps->pid, (ps->last->runtime - ps->first->runtime) / 1000000000.0, arg_show_cgroup ? ps->cgroup : ""); else fprintf(of, " %s [%i]%.01fms %s\n", time_to_graph(w - graph_start) + 5.0, ps_to_graph(j) + 14.0, escaped ? escaped : ps->name, ps->pid, (ps->last->runtime - ps->first->runtime) / 1000000.0, arg_show_cgroup ? ps->cgroup : ""); /* paint lines to the parent process */ if (ps->parent) { /* horizontal part */ fprintf(of, " \n", time_to_graph(starttime - graph_start), ps_to_graph(j) + 10.0, ps->parent->pos_x, ps_to_graph(j) + 10.0); /* one vertical line connecting all the horizontal ones up */ if (!ps->next) fprintf(of, " \n", ps->parent->pos_x, ps_to_graph(j) + 10.0, ps->parent->pos_x, ps->parent->pos_y); } j++; /* count boxes */ fprintf(of, "\n"); } /* last pass - determine when idle */ pid = getpid(); /* make sure we start counting from the point where we actually have * data: assume that bootchart's first sample is when data started */ ps = ps_first; while (ps->next_ps) { ps = ps->next_ps; if (ps->pid == pid) break; } if (!ps) ps = ps_first; /* need to know last node first */ ps->sample = ps->first; i = ps->sample->next->sampledata->counter; while (ps->sample->next && i<(n_samples-(arg_hz/2))) { double crt; double brt; int c; int ii; struct ps_sched_struct *sample_hz; ps->sample = ps->sample->next; sample_hz = ps->sample; for (ii = 0; (ii < (int)arg_hz/2) && sample_hz->next; ii++) sample_hz = sample_hz->next; /* subtract bootchart cpu utilization from total */ crt = 0.0; for (c = 0; c < n_cpus; c++) crt += sample_hz->sampledata->runtime[c] - ps->sample->sampledata->runtime[c]; brt = sample_hz->runtime - ps->sample->runtime; /* * our definition of "idle": * * if for (hz / 2) we've used less CPU than (interval / 2) ... * defaults to 4.0%, which experimentally, is where atom idles */ if ((crt - brt) < (interval / 2.0)) { idletime = ps->sample->sampledata->sampletime - graph_start; fprintf(of, "\n\n", idletime); fprintf(of, "\n", time_to_graph(idletime), -arg_scale_y, time_to_graph(idletime), ps_to_graph(pcount) + arg_scale_y); if (idletime > 1.0) fprintf(of, "%.01fs\n", time_to_graph(idletime) + 5.0, ps_to_graph(pcount) + arg_scale_y, idletime); else fprintf(of, "%.01fms\n", time_to_graph(idletime) + 5.0, ps_to_graph(pcount) + arg_scale_y, to_ms(idletime)); break; } i++; } } static void svg_top_ten_cpu(FILE *of, struct ps_struct *ps_first) { struct ps_struct *top[10]; struct ps_struct emptyps = {}; struct ps_struct *ps; int n, m; for (n = 0; n < (int) ELEMENTSOF(top); n++) top[n] = &emptyps; /* walk all ps's and setup ptrs */ ps = ps_first; while ((ps = get_next_ps(ps, ps_first))) { for (n = 0; n < 10; n++) { if (ps->total <= top[n]->total) continue; /* cascade insert */ for (m = 9; m > n; m--) top[m] = top[m-1]; top[n] = ps; break; } } fprintf(of, "Top CPU consumers:\n"); for (n = 0; n < 10; n++) fprintf(of, "%3.01fms - %s [%d]\n", 20 + (n * 13), to_ms(top[n]->total), top[n]->name, top[n]->pid); } static void svg_top_ten_pss(FILE *of, struct ps_struct *ps_first) { struct ps_struct *top[10]; struct ps_struct emptyps = {}; struct ps_struct *ps; int n, m; for (n = 0; n < (int) ELEMENTSOF(top); n++) top[n] = &emptyps; /* walk all ps's and setup ptrs */ ps = ps_first; while ((ps = get_next_ps(ps, ps_first))) { for (n = 0; n < 10; n++) { if (ps->pss_max <= top[n]->pss_max) continue; /* cascade insert */ for (m = 9; m > n; m--) top[m] = top[m-1]; top[n] = ps; break; } } fprintf(of, "Top PSS consumers:\n"); for (n = 0; n < 10; n++) fprintf(of, "%dK - %s [%d]\n", 20 + (n * 13), top[n]->pss_max, top[n]->name, top[n]->pid); } int svg_do(FILE *of, const char *build, struct list_sample_data *head, struct ps_struct *ps_first, int n_samples, int pscount, int n_cpus, double graph_start, double log_start, double interval, int overrun) { struct ps_struct *ps; double offset = 7; int r, c; sampledata = head; LIST_FIND_TAIL(link, sampledata, head); ps = ps_first; /* count initcall thread count first */ svg_do_initcall(of, head, 1, graph_start); ksize = kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0; /* then count processes */ while ((ps = get_next_ps(ps, ps_first))) { if (!ps_filter(ps)) pcount++; else pfiltered++; } psize = ps_to_graph(pcount) + (arg_scale_y * 2); esize = (arg_entropy ? arg_scale_y * 7 : 0); /* after this, we can draw the header with proper sizing */ svg_header(of, head, graph_start, arg_percpu ? n_cpus : 0); fprintf(of, "\n\n"); fprintf(of, "\n"); svg_io_bi_bar(of, head, n_samples, graph_start, interval); fprintf(of, "\n\n"); fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); svg_io_bo_bar(of, head, n_samples, graph_start, interval); fprintf(of, "\n\n"); for (c = -1; c < (arg_percpu ? n_cpus : 0); c++) { offset += 7; fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); svg_cpu_bar(of, head, n_cpus, c, graph_start); fprintf(of, "\n\n"); offset += 7; fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); svg_wait_bar(of, head, n_cpus, c, graph_start); fprintf(of, "\n\n"); } if (kcount) { offset += 7; fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); svg_do_initcall(of, head, 0, graph_start); fprintf(of, "\n\n"); } offset += 7; fprintf(of, "\n", 400.0 + (arg_scale_y * offset) + ksize); svg_ps_bars(of, head, n_samples, n_cpus, ps_first, graph_start, interval); fprintf(of, "\n\n"); fprintf(of, "\n"); r = svg_title(of, build, pscount, log_start, overrun); fprintf(of, "\n\n"); if (r < 0) return r; fprintf(of, "\n"); svg_top_ten_cpu(of, ps_first); fprintf(of, "\n\n"); if (arg_entropy) { fprintf(of, "\n", 400.0 + (arg_scale_y * offset) + ksize + psize); svg_entropy_bar(of, head, graph_start); fprintf(of, "\n\n"); } if (arg_pss) { fprintf(of, "\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize); svg_pss_graph(of, head, ps_first, graph_start); fprintf(of, "\n\n"); fprintf(of, "\n"); svg_top_ten_pss(of, ps_first); fprintf(of, "\n\n"); } /* fprintf footer */ fprintf(of, "\n\n"); return 0; } systemd-bootchart-233/src/svg.h000066400000000000000000000022021315600604400165700ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include int svg_do(FILE *of, const char *build, struct list_sample_data *head, struct ps_struct *ps_first, int n_samples, int pscount, int n_cpus, double graph_start, double log_start, double interval, int overrun); systemd-bootchart-233/src/terminal-util.c000066400000000000000000000054331315600604400205630ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include "fd-util.h" #include "macro.h" #include "terminal-util.h" #include "time-util.h" static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; int open_terminal(const char *name, int mode) { int fd, r; unsigned c = 0; /* * If a TTY is in the process of being closed opening it might * cause EIO. This is horribly awful, but unlikely to be * changed in the kernel. Hence we work around this problem by * retrying a couple of times. * * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 */ if (mode & O_CREAT) return -EINVAL; for (;;) { fd = open(name, mode, 0); if (fd >= 0) break; if (errno != EIO) return -errno; /* Max 1s in total */ if (c >= 20) return -errno; usleep(50 * USEC_PER_MSEC); c++; } r = isatty(fd); if (r < 0) { safe_close(fd); return -errno; } if (!r) { safe_close(fd); return -ENOTTY; } return fd; } int release_terminal(void) { static const struct sigaction sa_new = { .sa_handler = SIG_IGN, .sa_flags = SA_RESTART, }; _cleanup_close_ int fd = -1; struct sigaction sa_old; int r = 0; fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); if (fd < 0) return -errno; /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed * by our own TIOCNOTTY */ assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); if (ioctl(fd, TIOCNOTTY) < 0) r = -errno; assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); return r; } systemd-bootchart-233/src/terminal-util.h000066400000000000000000000025211315600604400205630ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #define ANSI_RED "\x1B[0;31m" #define ANSI_GREEN "\x1B[0;32m" #define ANSI_UNDERLINE "\x1B[0;4m" #define ANSI_HIGHLIGHT "\x1B[0;1;39m" #define ANSI_HIGHLIGHT_RED "\x1B[0;1;31m" #define ANSI_HIGHLIGHT_GREEN "\x1B[0;1;32m" #define ANSI_HIGHLIGHT_YELLOW "\x1B[0;1;33m" #define ANSI_HIGHLIGHT_BLUE "\x1B[0;1;34m" #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m" #define ANSI_NORMAL "\x1B[0m" #define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" /* Set cursor to top left corner and clear screen */ #define ANSI_HOME_CLEAR "\x1B[H\x1B[2J" int open_terminal(const char *name, int mode); int release_terminal(void); int make_null_stdio(void); systemd-bootchart-233/src/time-util.c000066400000000000000000000056241315600604400177100ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include "fd-util.h" #include "macro.h" #include "time-util.h" static clockid_t map_clock_id(clockid_t c) { /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on * those archs. */ switch (c) { case CLOCK_BOOTTIME_ALARM: return CLOCK_BOOTTIME; case CLOCK_REALTIME_ALARM: return CLOCK_REALTIME; default: return c; } } usec_t now(clockid_t clock_id) { struct timespec ts; assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0); return timespec_load(&ts); } usec_t timespec_load(const struct timespec *ts) { assert(ts); if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) return USEC_INFINITY; if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) return USEC_INFINITY; return (usec_t) ts->tv_sec * USEC_PER_SEC + (usec_t) ts->tv_nsec / NSEC_PER_USEC; } struct timespec *timespec_store(struct timespec *ts, usec_t u) { assert(ts); if (u == USEC_INFINITY) { ts->tv_sec = (time_t) -1; ts->tv_nsec = (long) -1; return ts; } ts->tv_sec = (time_t) (u / USEC_PER_SEC); ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); return ts; } clockid_t clock_boottime_or_monotonic(void) { static clockid_t clock = -1; int fd; if (clock != -1) return clock; fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); if (fd < 0) clock = CLOCK_MONOTONIC; else { safe_close(fd); clock = CLOCK_BOOTTIME; } return clock; } systemd-bootchart-233/src/time-util.h000066400000000000000000000067531315600604400177210ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include "attributes.h" typedef uint64_t usec_t; typedef uint64_t nsec_t; #define NSEC_FMT "%" PRIu64 #define USEC_FMT "%" PRIu64 #include "macro.h" typedef struct dual_timestamp { usec_t realtime; usec_t monotonic; } dual_timestamp; #define USEC_INFINITY ((usec_t) -1) #define NSEC_INFINITY ((nsec_t) -1) #define MSEC_PER_SEC 1000ULL #define USEC_PER_SEC ((usec_t) 1000000ULL) #define USEC_PER_MSEC ((usec_t) 1000ULL) #define NSEC_PER_SEC ((nsec_t) 1000000000ULL) #define NSEC_PER_MSEC ((nsec_t) 1000000ULL) #define NSEC_PER_USEC ((nsec_t) 1000ULL) #define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) #define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) #define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) #define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) #define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) #define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) #define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) #define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) #define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) #define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) #define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) #define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) usec_t now(clockid_t clock); static inline bool dual_timestamp_is_set(dual_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY)); } usec_t timespec_load(const struct timespec *ts) _pure_; struct timespec *timespec_store(struct timespec *ts, usec_t u); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) \ assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \ "xstrftime: " #buf "[] must be big enough") static inline usec_t usec_add(usec_t a, usec_t b) { usec_t c; /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't * overflow. */ c = a + b; if (c < a || c < b) /* overflow check */ return USEC_INFINITY; return c; } static inline usec_t usec_sub(usec_t timestamp, int64_t delta) { if (delta < 0) return usec_add(timestamp, (usec_t) (-delta)); if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */ return USEC_INFINITY; if (timestamp < (usec_t) delta) return 0; return timestamp - delta; } systemd-bootchart-233/src/unaligned.h000066400000000000000000000060321315600604400177440ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2014 Tom Gundersen systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include /* BE */ static inline uint16_t unaligned_read_be16(const void *_u) { const uint8_t *u = _u; return (((uint16_t) u[0]) << 8) | ((uint16_t) u[1]); } static inline uint32_t unaligned_read_be32(const void *_u) { const uint8_t *u = _u; return (((uint32_t) unaligned_read_be16(u)) << 16) | ((uint32_t) unaligned_read_be16(u + 2)); } static inline uint64_t unaligned_read_be64(const void *_u) { const uint8_t *u = _u; return (((uint64_t) unaligned_read_be32(u)) << 32) | ((uint64_t) unaligned_read_be32(u + 4)); } static inline void unaligned_write_be16(void *_u, uint16_t a) { uint8_t *u = _u; u[0] = (uint8_t) (a >> 8); u[1] = (uint8_t) a; } static inline void unaligned_write_be32(void *_u, uint32_t a) { uint8_t *u = _u; unaligned_write_be16(u, (uint16_t) (a >> 16)); unaligned_write_be16(u + 2, (uint16_t) a); } static inline void unaligned_write_be64(void *_u, uint64_t a) { uint8_t *u = _u; unaligned_write_be32(u, (uint32_t) (a >> 32)); unaligned_write_be32(u + 4, (uint32_t) a); } /* LE */ static inline uint16_t unaligned_read_le16(const void *_u) { const uint8_t *u = _u; return (((uint16_t) u[1]) << 8) | ((uint16_t) u[0]); } static inline uint32_t unaligned_read_le32(const void *_u) { const uint8_t *u = _u; return (((uint32_t) unaligned_read_le16(u + 2)) << 16) | ((uint32_t) unaligned_read_le16(u)); } static inline uint64_t unaligned_read_le64(const void *_u) { const uint8_t *u = _u; return (((uint64_t) unaligned_read_le32(u + 4)) << 32) | ((uint64_t) unaligned_read_le32(u)); } static inline void unaligned_write_le16(void *_u, uint16_t a) { uint8_t *u = _u; u[0] = (uint8_t) a; u[1] = (uint8_t) (a >> 8); } static inline void unaligned_write_le32(void *_u, uint32_t a) { uint8_t *u = _u; unaligned_write_le16(u, (uint16_t) a); unaligned_write_le16(u + 2, (uint16_t) (a >> 16)); } static inline void unaligned_write_le64(void *_u, uint64_t a) { uint8_t *u = _u; unaligned_write_le32(u, (uint32_t) a); unaligned_write_le32(u + 4, (uint32_t) (a >> 32)); } systemd-bootchart-233/src/utf8.c000066400000000000000000000207131315600604400166610ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2008-2011 Kay Sievers Copyright 2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ /* Parts of this file are based on the GLIB utf8 validation functions. The * original license text follows. */ /* gutf8.c - Operations on UTF-8 strings. * * Copyright (C) 1999 Tom Tromey * Copyright (C) 2000 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "macro.h" #include "utf8.h" bool unichar_is_valid(char32_t ch) { if (ch >= 0x110000) /* End of unicode space */ return false; if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ return false; if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ return false; if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ return false; return true; } static char hexchar(int x) { static const char table[16] = "0123456789abcdef"; return table[x & 15]; } static bool unichar_is_control(char32_t ch) { /* 0 to ' '-1 is the C0 range. DEL=0x7F, and DEL+1 to 0x9F is C1 range. '\t' is in C0 range, but more or less harmless and commonly used. */ return (ch < ' ' && ch != '\t' && ch != '\n') || (0x7F <= ch && ch <= 0x9F); } /* count of characters used to encode one unicode char */ static int utf8_encoded_expected_len(const char *str) { unsigned char c; assert(str); c = (unsigned char) str[0]; if (c < 0x80) return 1; if ((c & 0xe0) == 0xc0) return 2; if ((c & 0xf0) == 0xe0) return 3; if ((c & 0xf8) == 0xf0) return 4; if ((c & 0xfc) == 0xf8) return 5; if ((c & 0xfe) == 0xfc) return 6; return 0; } /* decode one unicode char */ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) { char32_t unichar; int len, i; assert(str); len = utf8_encoded_expected_len(str); switch (len) { case 1: *ret_unichar = (char32_t)str[0]; return 0; case 2: unichar = str[0] & 0x1f; break; case 3: unichar = (char32_t)str[0] & 0x0f; break; case 4: unichar = (char32_t)str[0] & 0x07; break; case 5: unichar = (char32_t)str[0] & 0x03; break; case 6: unichar = (char32_t)str[0] & 0x01; break; default: return -EINVAL; } for (i = 1; i < len; i++) { if (((char32_t)str[i] & 0xc0) != 0x80) return -EINVAL; unichar <<= 6; unichar |= (char32_t)str[i] & 0x3f; } *ret_unichar = unichar; return 0; } bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { const char *p; assert(str); for (p = str; length;) { int encoded_len, r; char32_t val; encoded_len = utf8_encoded_valid_unichar(p); if (encoded_len < 0 || (size_t) encoded_len > length) return false; r = utf8_encoded_to_unichar(p, &val); if (r < 0 || unichar_is_control(val) || (!newline && val == '\n')) return false; length -= encoded_len; p += encoded_len; } return true; } const char *utf8_is_valid(const char *str) { const uint8_t *p; assert(str); for (p = (const uint8_t*) str; *p; ) { int len; len = utf8_encoded_valid_unichar((const char *)p); if (len < 0) return NULL; p += len; } return str; } char *utf8_escape_invalid(const char *str) { char *p, *s; assert(str); p = s = malloc(strlen(str) * 4 + 1); if (!p) return NULL; while (*str) { int len; len = utf8_encoded_valid_unichar(str); if (len > 0) { s = mempcpy(s, str, len); str += len; } else { s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); str += 1; } } *s = '\0'; return p; } char *utf8_escape_non_printable(const char *str) { char *p, *s; assert(str); p = s = malloc(strlen(str) * 4 + 1); if (!p) return NULL; while (*str) { int len; len = utf8_encoded_valid_unichar(str); if (len > 0) { if (utf8_is_printable(str, len)) { s = mempcpy(s, str, len); str += len; } else { while (len > 0) { *(s++) = '\\'; *(s++) = 'x'; *(s++) = hexchar((int) *str >> 4); *(s++) = hexchar((int) *str); str += 1; len --; } } } else { s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); str += 1; } } *s = '\0'; return p; } /* expected size used to encode one unicode char */ static int utf8_unichar_to_encoded_len(char32_t unichar) { if (unichar < 0x80) return 1; if (unichar < 0x800) return 2; if (unichar < 0x10000) return 3; if (unichar < 0x200000) return 4; if (unichar < 0x4000000) return 5; return 6; } /* validate one encoded unicode char and return its length */ int utf8_encoded_valid_unichar(const char *str) { int len, i, r; char32_t unichar; assert(str); len = utf8_encoded_expected_len(str); if (len == 0) return -EINVAL; /* ascii is valid */ if (len == 1) return 1; /* check if expected encoded chars are available */ for (i = 0; i < len; i++) if ((str[i] & 0x80) != 0x80) return -EINVAL; r = utf8_encoded_to_unichar(str, &unichar); if (r < 0) return r; /* check if encoded length matches encoded value */ if (utf8_unichar_to_encoded_len(unichar) != len) return -EINVAL; /* check if value has valid range */ if (!unichar_is_valid(unichar)) return -EINVAL; return len; } systemd-bootchart-233/src/utf8.h000066400000000000000000000032621315600604400166660ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "attributes.h" #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" bool unichar_is_valid(char32_t c); const char *utf8_is_valid(const char *s) _pure_; bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) char *utf8_escape_invalid(const char *s); char *utf8_escape_non_printable(const char *str); int utf8_encoded_valid_unichar(const char *str); int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar); static inline bool utf16_is_surrogate(char16_t c) { return (0xd800 <= c && c <= 0xdfff); } static inline bool utf16_is_trailing_surrogate(char16_t c) { return (0xdc00 <= c && c <= 0xdfff); } static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) { return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; } systemd-bootchart-233/src/util.c000066400000000000000000000024651315600604400167540ustar00rootroot00000000000000/*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include "build.h" #include "macro.h" #include "util.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); int saved_argc = 0; char **saved_argv = NULL; size_t page_size(void) { static thread_local size_t pgsz = 0; long r; if (_likely_(pgsz > 0)) return pgsz; r = sysconf(_SC_PAGESIZE); assert(r > 0); pgsz = (size_t) r; return pgsz; } int version(void) { puts(PACKAGE_STRING "\n" SYSTEMD_FEATURES); return 0; } systemd-bootchart-233/src/util.h000066400000000000000000000071551315600604400167620ustar00rootroot00000000000000#pragma once /*** This file is part of systemd. Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include #include #include #include #include #include #include "attributes.h" #include "macro.h" size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) static inline const char* yes_no(bool b) { return b ? "yes" : "no"; } static inline const char* true_false(bool b) { return b ? "true" : "false"; } static inline const char* one_zero(bool b) { return b ? "1" : "0"; } #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) #define NULSTR_FOREACH_PAIR(i, j, l) \ for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) extern int saved_argc; extern char **saved_argv; /** * Normal qsort requires base to be nonnull. Here were require * that only if nmemb > 0. */ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { if (nmemb <= 1) return; assert(base); qsort(base, nmemb, size, compar); } /** * Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ static inline void memcpy_safe(void *dst, const void *src, size_t n) { if (n == 0) return; assert(src); memcpy(dst, src, n); } #define memzero(x,l) (memset((x), 0, (l))) #define zero(x) (memzero(&(x), sizeof(x))) static inline void *mempset(void *s, int c, size_t n) { memset(s, c, n); return (uint8_t*)s + n; } static inline void _reset_errno_(int *saved_errno) { errno = *saved_errno; } #define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno static inline int negative_errno(void) { /* This helper should be used to shut up gcc if you know 'errno' is * negative. Instead of "return -errno;", use "return negative_errno();" * It will suppress bogus gcc warnings in case it assumes 'errno' might * be 0 and thus the caller's error-handling might not be triggered. */ assert_return(errno > 0, -EINVAL); return -errno; } static inline unsigned u64log2(uint64_t n) { #if __SIZEOF_LONG_LONG__ == 8 return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; #else #error "Wut?" #endif } static inline unsigned u32ctz(uint32_t n) { #if __SIZEOF_INT__ == 4 return __builtin_ctz(n); #else #error "Wut?" #endif } static inline unsigned log2i(int x) { assert(x > 0); return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1; } static inline unsigned log2u(unsigned x) { assert(x > 0); return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; } static inline unsigned log2u_round_up(unsigned x) { assert(x > 0); if (x == 1) return 0; return log2u(x - 1) + 1; } int version(void); systemd-bootchart-233/tests/000077500000000000000000000000001315600604400161775ustar00rootroot00000000000000systemd-bootchart-233/tests/run000077500000000000000000000012001315600604400167220ustar00rootroot00000000000000#! /bin/sh d= cleanup() { if [ -n "$d" ]; then d= rm -rf "$d" fi } trap cleanup EXIT d=`mktemp -d` test_runs=0 test_failures=0 t() { "$@" local r=$? : $((test_runs=test_runs+1)) if [ $r -ne 0 ]; then : $((test_failures=test_failures+1)) echo "not ok $test_runs - $*" fi } echo 1..3 t ./systemd-bootchart -o "$d" -n 2 -r t ./systemd-bootchart -o "$d" -n 10 -r t ./systemd-bootchart -o "$d" -n 10 -r -p if [ $test_failures -ne 0 ]; then echo "# Failed $test_failures out of $test_runs tests" exit 1 fi systemd-bootchart-233/units/000077500000000000000000000000001315600604400161775ustar00rootroot00000000000000systemd-bootchart-233/units/.gitignore000066400000000000000000000000331315600604400201630ustar00rootroot00000000000000/systemd-bootchart.service systemd-bootchart-233/units/systemd-bootchart.service.in000066400000000000000000000012161315600604400236410ustar00rootroot00000000000000# This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # Note: it's usually a better idea to run systemd-bootchart via the # init= kernel command line switch. See the man page for details. [Unit] Description=Boot Process Profiler Documentation=man:systemd-bootchart.service(1) man:bootchart.conf(5) DefaultDependencies=no [Service] ExecStart=@rootlibexecdir@/systemd-bootchart -r [Install] WantedBy=sysinit.target