pax_global_header00006660000000000000000000000064126611613360014517gustar00rootroot0000000000000052 comment=807ac2f8661873441422b4aad14069ec6940aa68 needrestart-2.6/000077500000000000000000000000001266116133600137065ustar00rootroot00000000000000needrestart-2.6/.gitignore000066400000000000000000000001521266116133600156740ustar00rootroot00000000000000autom4te.cache/ man/Makefile perl/MYMETA.json perl/MYMETA.yml perl/Makefile perl/blib/ perl/pm_to_blib *~ needrestart-2.6/AUTHORS000066400000000000000000000000751266116133600147600ustar00rootroot00000000000000needrestart =========== Thomas Liske needrestart-2.6/COPYING000066400000000000000000000431221266116133600147430ustar00rootroot00000000000000 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 Library 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 Library General Public License instead of this License. needrestart-2.6/ChangeLog000066400000000000000000000335401266116133600154650ustar00rootroot00000000000000needrestart (2.6) unstable; urgency=high * [Bug] Do not notify system users via email. (Debian Bug#812399 by Marc Haber ) * [Bug] Do no restart services in interactive restart mode while debconf's noninteractive frontend is used. (Debian Bug#803249 by Felix Geyer ) * [Bug] Fix broken detection of old mappings due to regression introduced in v2.3 (commit acf6a07). (Debian Bug#810970 by Andreas Schmidt ) -- Thomas Liske Wed, 17 Feb 2016 22:14:32 +0100 needrestart (2.5) unstable; urgency=medium * [Bug] Fix broken kernel detection due to syntax error. (Debian Bug#810031 by Martin Steigerwald ) -- Thomas Liske Tue, 05 Jan 2016 23:17:53 +0100 needrestart (2.4) unstable; urgency=medium * [Bug] Drop unused dependency on File::Slurp. (Debian Bug#799733 by Christoph Anton Mitterer ) (Debian Bug#799734 by Sven Hartge ) * [Bug] Add user@\d+.service to override_rc. (Debian Bug#788380 by Shirish Agarwal ) * [Bug] Add override for systemd-logind due to another systemd regression. (Debian Bug#800718 by Sven Hartge ) * [Bug] Fix grammar in hook scripts. (Debian Bug#805980 by Justin B Rye ) * [Bug] Fix kernel detection on non x86* arch. (Debian Bug#800720 by Sven Hartge ) * [Kernel] Extract kernel version on non-x86(_64) archs (allows ABI checks). -- Thomas Liske Fri, 01 Jan 2016 21:54:47 +0100 needrestart (2.3) unstable; urgency=medium * [Bug] Add lightdm to override. (Debian Bug#791649 by Martin Steigerwald ) * [Bug] Do not try container detection in user mode. (Debian Bug#791665 by Ansgar Burchardt ) * [Bug] Remove unsupported HTML markups from notifications. (Debian Bug#791664 by Ansgar Burchardt ) * [Bug] Compare inodes of mapped files more reliable for chrooted processes. (github issue #11 by Markus Frosch ) * [Kernel] Skip kernel detection within containers. * [UI] Add a quiet option to drop any progress messages. (Debian Bug#791708 by Rodrigo Campos ) * [Bug] Do not handle user services as system services. (Debian Bug#792032 by Ansgar Burchardt ) * [Bug] Fix cutting path names read from /proc/PID/maps at spaces resulting in false-positives. -- Thomas Liske Sat, 19 Sep 2015 20:38:19 +0200 needrestart (2.2) unstable; urgency=medium * [regression] Processes using chroot were always detected as obsolete since missing binaries in /proc/PID/root/. (Debian Bug#786584 by François Mescam ) -- Thomas Liske Tue, 26 May 2015 23:56:11 +0200 needrestart (2.1) unstable; urgency=medium * [Bug] Ignore /usr/bin/apt-get. (Debian Bug#784237 by Thijs Kinkhorst ) * [Bug] Add override for systemd's emergency.service and rescue.service. (Debian Bug#784437) * [Bug] Ignore Oil Runtime Compiler's JIT files. (Debian Bug#786374 by Francois Mescam ) * [Bug] Fix 2c037bc did broke the progressbar. (Related to Debian Bug#768124) * [Cont] Detect and suggest to restart containers: - docker - LXC (Debian Bug#783181 by Brian Minton ) * [Core] Add nagios plugin mode (-p). (github issue #5 by Ludovic Gasc [@GMLudo]) * [Core] Use /proc/$PID/root to scan for files fixing false positives on containers (i.e. LXC) using bind mounts. (Debian Bug#783181 by Brian Minton ) * [Interp] Skip scanning files with Interp/* if cwd is unknown. (Debian Bug#779832 by wforumw ) * [Interp] Skip scanning files with Interp/* if cwd is unknown. (Debian Bug#779832 by wforumw ) * [Kernel] Add kernel hints option not requiring an acknowledgement by the user. (Debian Bug#769811 by Axel Beckert ) * [Kernel] Take version number comparing stuff from Dpkg::Version to compare kernel versions correctly. (Debian Bug#781657 by Martin Steigerwald ) * [UI] Improve restart query in interactive mode (stdio). (Debian Bug#772859 by Axel Beckert ) -- Thomas Liske Fri, 22 May 2015 01:45:17 +0200 needrestart (2.0) unstable; urgency=medium * [regression] List commands in list mode. (Debian Bug#764042 by Paul Wise ) * Add a conf.d/ directory. (Debian Bug#764043 by Paul Wise ) * [UI] Fix empty current/expected kernel version string used by debconf template. (Debian Bug#764917 by Laurent Bonnaud ) * Don't blacklist services by default but use a new override_rc option to don't restart some critical services by default. (Debian Bug#763937 by Christoph Anton Mitterer ) * Don't restart services greylisted in override_rc in auto mode. (Debian Bug#770937 by Axel Beckert ) * [UI] Disable progress bar while running non-interactive. (Debian Bug#768124 by Phillip Berndt ) * [UI] Fix warning on uninitialized values while reading from /dev/stdin. (Debian Bug#768124 by Phillip Berndt ) * [Interp] Add basic Java detection support. * Add PolicyKit action file to allow needrestart-session to run needrestart as root. * [UI] Add `-f ` CLI parameter to allow to overwrite the DEBIAN_FRONTEND environment variable used by debconf(7). -- Thomas Liske Fri, 23 Jan 2015 00:46:13 +0100 needrestart (1.2) unstable; urgency=medium * Prepare po-debconf usage and add German translation. (Debian Bug#761068 by David Prévot ) * Drop dependency on Term::ProgressBar::Simple. (Debian Bug#761192 by Thijs Kinkhorst ) * Fix blacklist to match upgraded binaries (dpkg). (Debian Bug#761346 by Paul Wise ) * Fix detection of unit names on systemd 215+. (Debian Bug#762312 by Sven Hartge ) * Ignore special paths (SYSV IPC, DRM, /dev), fixing some false positives. * Add service blacklist configuration option to fix display manager blacklisting with systemd. * Handle restarts of systemd manager and sysv init using their specific commands. (Debian Bug#762528 by Paul Wise ) -- Thomas Liske Sun, 28 Sep 2014 23:48:42 +0200 needrestart (1.1) unstable; urgency=medium * Ignore DHCP clients. (Debian Bug#752111 by Axel Beckert ) * Add options allowing to select which check should be performed. (Proposed by Axel Beckert ) -- Thomas Liske Sat, 16 Aug 2014 09:57:29 +0200 needrestart (1.0) unstable; urgency=medium * Fix grammar errors and use a additional debconf template. (Debian Bug#748652 by Justin B Rye ) * Ignore device ID in /proc//maps on kFreeBSD. (Reported by Axel Beckert ). * Ignore device ID for unnamed devices due to broken implementation on btrfs. (Debian Bug#750734 by Frederik Himpe ) * Skip scanning of needrestart process. (Debian Bug#751877 by Thijs Kinkhorst ) * [UI] Drop UI specific progress indicators, use Term::ProgressBar::Simple to minimize disruption of the terminal. (Debian Bug#748758 by Thijs Kinkhorst ) * [UI] Support 'backup' capability of Debconf. * [Interp] Fix include path retrieval on python3. (Debian Bug#750589 by Cristian Ionescu-Idbohrn ) * [Interp] Handle errors on python include path retrieval gracefully. (Debian Bug#750589 by Cristian Ionescu-Idbohrn ) -- Thomas Liske Tue, 17 Jun 2014 15:21:15 +0200 needrestart (0.9) unstable; urgency=medium * Drop external dependency on strings command from binutils. * Fix "uninitialized value" by apparent kernel threads. (Debian Bug#746363 by Axel Beckert ) * Read kernel version from x86 kernel boot header and handle uncompressed kernel images. (Debian Bug#746550 by Axel Beckert ) * Several small bugfixes: - [Interp] initial source file detection broken due using getopt instead of getopts (Debian Bug#746363 by Axel Beckert ) - [UI] fix newlines in Debconf template - [UI] fix "No such file or directory" triggered by stdio (Debian Bug#746550 by Axel Beckert ) - [Interp] Use source file instead of /proc//exe to find package. -- Thomas Liske Sun, 11 May 2014 22:48:42 +0200 needrestart (0.8) unstable; urgency=low * Fix non-numeric argument on progress_prep call. (Debian Bug#744961 by Cristian Ionescu-Idbohrn ) * Feature: interpreter support enables needrestart to look for obsolete source files in scripting languages: - Perl: using Module::ScanDeps - Python: using home made source file scanning - Ruby: using home made source file scanning * Feature: detect running on obsolete kernels (Debian Bug#745270 by Paul Wise ) * NeedRestart::UI::Dialog: has been dropped * NeedRestart::UI::stdio: add mass processing * Several small bugfixes. -- Thomas Liske Sun, 27 Apr 2014 10:15:35 +0200 needrestart (0.7) unstable; urgency=medium * Improved rc script detection, e.g.: previous releases failed to detect apache2's init script after upgrading libssl1.0.0. * Handle Linux VServer naming convention on deleted binaries. (Thanks to Phillip Berndt [@phillipberndt]) * Support GNU formatted device ids. (github issue #1 by Phillip Berndt [@phillipberndt]) * Hooks: Use only available package managers. * Hooks: Ignore hooks not returning any rc scripts (fixes detecting apache2's rc script). * Hooks: Prefer rc scripts w/ matching pid (fixes calling unnecessary rc scripts like libvirt-guests). * Improve rc script detection by using a two pass analysis. * Fallback to NeedRestart::UI::stdio while being verbose. (Debian Bug#744000 by Paul Wise ) * Add default UI configuration option. (Debian Bug#744001 by Paul Wise ) * Apply blacklist while processing parent processes. (Debian Bug#744002 by Paul Wise ) * Apply Debian's 01-makefile-fix.diff upstream. -- Thomas Liske Mon, 14 Apr 2014 21:50:15 +0200 needrestart (0.6) unstable; urgency=low * Add lightdm to blacklist. (Debian Bug#735027 by Michael Gilbert ) * Print eval exception message on config file errors. * Use systemd if available. (Debian Bug#731028 by Paul Wise ) * Use service to run traditional SysV scripts. * Change batch processing output. * Print full restart commands in list mode. (Debian Bug#731028 by Paul Wise ) -- Thomas Liske Mon, 07 Apr 2014 22:52:18 +0200 needrestart (0.5) unstable; urgency=low * Ignore mapped files in /tmp. * Handle LSB tags case insensitivly. (Debian Bug#731165 by Christian Ionescu-Idbohrn ) * Prevent config file in dpkg.cfg.d to break dpkg after removing needrestart. (Debian Bug#732461 by Andreas Beckmann ) -- Thomas Liske Thu, 02 Jan 2014 19:55:49 +0100 needrestart (0.4) unstable; urgency=low * Fix spelling: - typo in debconf template (s/restartet/restarted/;) (Debian Bug#723935 by Axel Beckert ) - debconf template title (s/orphaned/outdated/;) (Debian Bug#723935 by Justin B Rye ) * Fix progress bar increase to grow up to 100%: - binaries were counted twice - kernel threads did not increase progress * Demand restart of deleted binaries. * Add sudo binary to example blacklist. (Debian Bug#725937 by Jim Barber ) * Drop version number from man page. (Debian Bug#729997 by Raf Czlonka ) * NeedRestart::UI::Debconf: Fix return code handling if readline is used as debconf frontend. (Debian Bug#729997 by Raf Czlonka ) -- Thomas Liske Thu, 28 Nov 2013 19:30:06 +0100 needrestart (0.3) unstable; urgency=low * Fix typo reported by Patrick Matthäi. * Add man page provided by Patrick Matthäi (Debian). * Offer restart on non-existing mappings. * Add PacMan hook. * Be more fault-tolerant in batch mode. * Provide a more sophisticated apt/dpkg trigger. * Fix ignored -r command line parameter. (Debian Bug#721809 by Axel Beckert ) * Ignore forked/detached daemon childs (pidfile heuristic). (Debian Bug#721810 by Axel Beckert ) * Provide modular UI including debconf and dialog based frontends. * Ignore binaries due blacklist config option. -- Thomas Liske Sat, 14 Sep 2013 12:55:16 +0200 needrestart (0.2) unstable; urgency=low * Support (l)ist only, (i)nteractive restart and (a)utomaticly restart modes. * Supply apt.conf.d script to call needrestart on every upgrade. * Drop dependency on (Debian's) run-parts. * Drop Term::Query dependency. * Ignore rc scripts to be run in other run-levels. * Add batch mode. -- Thomas Liske Tue, 02 Apr 2013 21:51:48 +0200 needrestart (0.1) unstable; urgency=low * Initial release. -- Thomas Liske Fri, 29 Mar 2013 19:40:09 +0100 needrestart-2.6/INSTALL000066400000000000000000000002611266116133600147360ustar00rootroot00000000000000Prerequisites ============= Perl ---- Module::Find Module::ScanDeps Proc::ProcessTable Sort::Naturally Term::ProgressBar::Simple Misc ---- po-debconf (on Debian derivates) needrestart-2.6/Makefile000066400000000000000000000027401266116133600153510ustar00rootroot00000000000000all: cd perl && perl Makefile.PL PREFIX=$(PREFIX) INSTALLDIRS=vendor cd perl && $(MAKE) install: all cd perl && $(MAKE) install mkdir -p "$(DESTDIR)/etc/needrestart/hook.d" cp hooks/* "$(DESTDIR)/etc/needrestart/hook.d/" cp ex/needrestart.conf "$(DESTDIR)/etc/needrestart/" mkdir -p "$(DESTDIR)/etc/needrestart/conf.d" cp ex/conf.d/* "$(DESTDIR)/etc/needrestart/conf.d/" mkdir -p "$(DESTDIR)/etc/needrestart/notify.d" cp ex/notify.d/* "$(DESTDIR)/etc/needrestart/notify.d/" which apt-get > /dev/null && \ mkdir -p "$(DESTDIR)/etc/apt/apt.conf.d" && cp ex/apt/needrestart-apt_d "$(DESTDIR)/etc/apt/apt.conf.d/99needrestart" && \ mkdir -p "$(DESTDIR)/etc/dpkg/dpkg.cfg.d" && cp ex/apt/needrestart-dpkg_d "$(DESTDIR)/etc/dpkg/dpkg.cfg.d/needrestart" && \ mkdir -p "$(DESTDIR)/usr/lib/needrestart" && cp ex/apt/dpkg-status ex/apt/apt-pinvoke "$(DESTDIR)/usr/lib/needrestart" || true which debconf > /dev/null && \ mkdir -p "$(DESTDIR)/usr/share/needrestart" && \ po2debconf ex/debconf/needrestart.templates > "$(DESTDIR)/usr/share/needrestart/needrestart.templates" || true mkdir -p "$(DESTDIR)/usr/share/polkit-1/actions" cp ex/polkit/net.fiasko-nw.needrestart.policy "$(DESTDIR)/usr/share/polkit-1/actions/" mkdir -p "$(DESTDIR)/usr/sbin" cp needrestart "$(DESTDIR)/usr/sbin/" mkdir -p "$(DESTDIR)/usr/lib/needrestart" cp lib/vmlinuz-get-version "$(DESTDIR)/usr/lib/needrestart/" clean: [ ! -f perl/Makefile ] || ( cd perl && $(MAKE) realclean ) needrestart-2.6/NEWS000066400000000000000000000047651266116133600144210ustar00rootroot00000000000000Changes in 2.1 ============== containers (LXC et. al.) ------------------------ Needrestart tries to detect if a process runs inside a container like LXC or docker. There are special scanner packages (NeedRestart::CONT::*) which implements the implementation specific detection and restarting. More information: README.Cont.md Changes in 0.8 ============== interpreters (Perl et. al.) --------------------------- Needrestart tries to detect if interpreters are using old source files. There are special scanner packages (NeedRestart::Interp::*) which implements the interpreter specific detection. Since most interpreter languages allow dynamic source code loading (eval) and we are using a home made source parcing there is a reasonable possibility to miss outdated source files. More information: README.Interp.md kernel upgrades --------------- Needrestart tries to detect if an pending kernel upgrade is available. It will only suggest a reboot. More information: README.Kernel.md UI -- The UI implementation NeedRestart::UI::Dialog has been dropped. Changes in 0.6 ============== systemd support --------------- If needrestart detects a running systemd it is used as primary source to identify service names. This speedups the detection significantly. The traditional detection using package managers is still used if systemd is not running or systemctl does not return a service name for a PID. Changes in 0.3 ============== blacklisting ------------ It might be a bad idea to (auto) restart certain daemons. Therefor a new config option is available to ignore binaries by matching a regex. The supplied default configuration ignores dbus, NetworkManager and various display managers. user interface -------------- The old basic user interface has been replace by a modular approach. User interfaces are now implemented in the NeedRestart::UI::* packages. New UI packages can be added by putting them into perl's search path. Using Module::Find to load any NeedRestart::UI::* package. Packages failing to load are ignored. The following UI implementations are shipped: * NeedRestart::UI::Debconf - use Debian's debconf front end * NeedRestart::UI::Dialog - use UI::Dialog * NeedRestart::UI::stdio - the simple old UI sophisticated apt/dpkg trigger ------------------------------ The new apt/dpkg trigger only runs needrestart if there was a package unpacked by dpkg and no error has occurred during the dpkg run. The scripts and config files required for the apt and dpkg integration are installed by default. needrestart-2.6/README.Cont.md000066400000000000000000000013731266116133600160730ustar00rootroot00000000000000needrestart - container support =============================== If needrestart has found a process using obsolete binaries it checks if the process is part of a container. If the process is part of a container it might not be possible to restart it using Sys-V/systemd. There are special packages (NeedRestart::CONT::*) implementing the container detection and restarting. NeedRestart::CONT::docker ------------------------- Recognized by: cgroup path (`/system.slice/docker-*.scope`) For each container which should be restarted needrestart calls `docker restart $NAME`. NeedRestart::CONT::LXC ---------------------- Recognized by: cgroup path (`/lxc/*`) For each container which should be restarted needrestart calls `lxc-stop --reboot --name $NAME`. needrestart-2.6/README.Interp.md000066400000000000000000000042111266116133600164230ustar00rootroot00000000000000needrestart - interpreter support ================================= Needrestart checks running processes for using obsolete binaries. If no obsolete binary was found needrestart scans for known interpreters. There are special packages (NeedRestart::Interp::*) implementing the source code file list extraction. The executable (/proc//exec) is used to detect the running interpreter. Whenever source files where located their ctime values are retrieved. If any of the source files has been changed after process creation time a restart of the pid is triggered. This is no perfect valuation since there are no inode information like for loaded binary objects nor has needrestart any chance to get a verified list of sourced files.. NeedRestart::Interp::Java ------------------------- Recognized binaries: /.+/bin/java Find source file by: n/a Try to detected loaded \.(class|jar) files by looking at open files. This approach will not reliably detect loaded java files. Finding the original command used to launch a java program is not that easy. Since there is no shebang we will not find any data about the original command in /proc/$PID. Running on systemd will allow us to find the service name due to the cgroup name - seems to work for java daemons like tomcat6. NeedRestart::Interp::Perl ------------------------- Recognized binaries: /usr/(local/)?bin/perl Find source file by: command line interpretation We are using `Module::ScanDeps` to find used packages. This should work on any static loaded packages, dynamic stuff will fail. NeedRestart::Interp::Python --------------------------- Recognized binaries: /usr/(local/)?bin/python.* Find source file by: command line interpretation The source file is scanned for 'import' and 'from' lines. All paths in `sys.path` are scanned for the module files. This should work on any static loaded modules. NeedRestart::Interp::Ruby ------------------------- Recognized binaries: /usr/(local/)?bin/ruby.* Find source file by: command line interpretation The source file is scanned for 'load' and 'require' lines. All paths in `$:` are scanned for the module files. This should work on any static loaded modules. needrestart-2.6/README.batch.md000066400000000000000000000011671266116133600162520ustar00rootroot00000000000000needrestart - batch mode ======================== Needrestart can be run in batch mode: ```console # needrestart -b NEEDRESTART-VER: 2.1 NEEDRESTART-KCUR: 3.19.3-tl1+ NEEDRESTART-KEXP: 3.19.3-tl1+ NEEDRESTART-KSTA: 1 NEEDRESTART-SVC: systemd-journald.service NEEDRESTART-SVC: systemd-machined.service NEEDRESTART-CONT: LXC web1 ``` Batch mode can be used to use the results of needrestart in other scripts. While needrestart is run in batch mode it will never show any UI dialogs nor restart anything. The output format is complient to the *apt-dater protocol*[1]. [1] https://github.com/DE-IBH/apt-dater-host/blob/master/doc/ needrestart-2.6/README.md000066400000000000000000000040551266116133600151710ustar00rootroot00000000000000needrestart =========== about ----- *needrestart* checks which daemons need to be restarted after library upgrades. It is inspired by *checkrestart* from the *debian-goodies* package. There are some hook scripts in the ``ex/`` directory (to be used with *apt* and *dpkg*. The scripts will call *needrestart* after any package installation/upgrades. *needrestart* should work on GNU/Linux. It has limited functionality on GNU/kFreeBSD since /proc//maps does not show removed file links. restarting services ------------------- *needrestart* supports but does not require systemd (available since v0.6). If systemd is not available or does not return a service name *needrestart* uses hooks to identify the corresponding System V init script. The shipped hooks support the following package managers: * *dpkg* * *rpm* * *pacman* The *service* command is used to run the tradiditional System V init script. frontends --------- *needrestart* uses a modular aproach based on perl packages providing the user interface. The following frontends are shipped: * *NeedRestart::UI::Debconf* using *debconf* * *NeedRestart::UI::stdio* fallback using stdio interaction interpreters ------------ *needrestart* 0.8 brings an interpreter scanning feature. Interpreters not only map binary (shared) objects but also use plaintext source files. The interpreter detection tries to check for outdated source files since they may contain security issues, too. This is only a heuristic and might fail to detect all relevant source files. The following interpreter scanners are shipped: * *NeedRestart::Interp::Java* * *NeedRestart::Interp::Perl* * *NeedRestart::Interp::Python* * *NeedRestart::Interp::Ruby* containers ---------- *needrestart* 2.1 detects some container technologies. If a process is part of a container it might not be possible to restart it using Sys-V/systemd. There are special packages (NeedRestart::CONT::*) implementing the container detection and restarting. The following container detectors are shipped: * *NeedRestart::CONT::docker* * *NeedRestart::CONT::LXC* needrestart-2.6/README.nagios.md000066400000000000000000000012461266116133600164470ustar00rootroot00000000000000needrestart - nagios plugin mode ================================ Needrestart can be used as a nagios plugin: ```console # needrestart -p CRIT - Kernel: 3.16.0-4-amd64, Services: none, Containers: 1 (!), Sessions: none|Kernel=0;0;;0;2 Services=0;;0;0 Containers=1;;0;0 Sessions=0;0;;0 ``` Since needrestart requires root privileges to scan processes of other users you should use sudo. Needrestart ships some example files to run needrestart as nagios plugin using sudo: - `ex/nagios/check_needrestart` - calls sudo to invoke needrestart - `ex/nagios/needrestart` - sudo(8) config allowing nagios to run needrestart as root - `ex/nagios/plugin.conf` - nagios(8) integration needrestart-2.6/ex/000077500000000000000000000000001266116133600143225ustar00rootroot00000000000000needrestart-2.6/ex/99needrestart000066400000000000000000000005511266116133600167500ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Call needrestart after package upgrades/installations and check # for pending service restarts. This is a quite simple approach, # a more sophisticated approach can be found in the $SOURCES/ex/apt/ # directory. # DPkg::Post-Invoke {"test -x /usr/sbin/needrestart && /usr/sbin/needrestart || true"; }; needrestart-2.6/ex/apt/000077500000000000000000000000001266116133600151065ustar00rootroot00000000000000needrestart-2.6/ex/apt/apt-pinvoke000077500000000000000000000014501266116133600172710ustar00rootroot00000000000000#!/bin/sh # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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. # RUNDIR=/run/needrestart # dpkg had an error... exit (silently) if [ -e "$RUNDIR/errored" ]; then [ -e "$RUNDIR/unpacked" ] && echo "needrestart is being skipped since dpkg has failed" rm -f "$RUNDIR/errored" exit 0 fi if [ -e "$RUNDIR/unpacked" ]; then rm -f "$RUNDIR/unpacked" exec /usr/sbin/needrestart fi needrestart-2.6/ex/apt/dpkg-status000077500000000000000000000016071266116133600173060ustar00rootroot00000000000000#!/bin/sh # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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. # RUNDIR=/run/needrestart mkdir -p "$RUNDIR" touched=0 errored=0 while read tag p0 p1 p2 p3 p4 pp; do if [ "$tag" = 'status:' -a "$p1" = 'unpacked' ]; then if [ "$touched" = 0 ]; then touch "$RUNDIR/unpacked" touched=1 fi else if [ "$tag" = 'status:' -a "$p1" = ':' -a "$p2" = 'error' -a "$p3" = ':' ]; then if [ "$errored" = 0 ]; then touch "$RUNDIR/errored" errored=1 fi fi fi done needrestart-2.6/ex/apt/needrestart-apt_d000066400000000000000000000005221266116133600204350ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Call needrestart after package upgrades/installations and check # for pending service restarts. Should only be triggered if there # was no error during installation. # DPkg::Post-Invoke {"test -x /usr/lib/needrestart/apt-pinvoke && /usr/lib/needrestart/apt-pinvoke || true"; }; needrestart-2.6/ex/apt/needrestart-dpkg_d000066400000000000000000000004221266116133600205750ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Scan for (successfully) installed packages, # triggers needrestart in apt's Dpkg::Post-Invoke # hook. status-logger=(test -x /usr/lib/needrestart/dpkg-status && /usr/lib/needrestart/dpkg-status || cat > /dev/null) needrestart-2.6/ex/conf.d/000077500000000000000000000000001266116133600154715ustar00rootroot00000000000000needrestart-2.6/ex/conf.d/README.needrestart000066400000000000000000000003611266116133600206700ustar00rootroot00000000000000Files ending with .conf and located in the /etc/needrestart/conf.d directory are parsed by needrestart's default configuration file. Files are parsed in order (using Perl's sort sub) and override or modify any previously set config option. needrestart-2.6/ex/debconf/000077500000000000000000000000001266116133600157225ustar00rootroot00000000000000needrestart-2.6/ex/debconf/needrestart.templates000066400000000000000000000022331266116133600221620ustar00rootroot00000000000000Template: needrestart/ui-query_pkgs_title Type: title _Description: Daemons using outdated libraries Template: needrestart/ui-query_pkgs Type: multiselect Choices: ${PKGS} _Description: Which services should be restarted? Template: needrestart/ui-kernel_announce_abi Type: note _Description: Newer kernel available The currently running kernel version is ${KVERSION} and there is an ABI compatible upgrade pending. . Restarting the system to load the new kernel will not be handled automatically, so you should consider rebooting. Template: needrestart/ui-kernel_announce_ver Type: note _Description: Newer kernel available The currently running kernel version is ${KVERSION} which is not the expected kernel version ${EVERSION}. . Restarting the system to load the new kernel will not be handled automatically, so you should consider rebooting. Template: needrestart/ui-kernel_title Type: title _Description: Pending kernel upgrade Template: needrestart/ui-query_conts_title Type: title _Description: Containers using outdated libraries Template: needrestart/ui-query_conts Type: multiselect Choices: ${CONTS} _Description: Which containers should be restarted? needrestart-2.6/ex/debconf/po/000077500000000000000000000000001266116133600163405ustar00rootroot00000000000000needrestart-2.6/ex/debconf/po/de.pot000066400000000000000000000041721266116133600174600ustar00rootroot00000000000000# German debconf translation for the needrestart package. # Copyright (C) 2014 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the needrestart package. # Thomas Liske , 2014. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: needrestart 1.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-09-11 21:59+0200\n" "PO-Revision-Date: 2014-09-20 17:31+0200\n" "Last-Translator: Thomas Liske \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: title #. Description #: ../needrestart.templates:1001 msgid "Daemons using outdated libraries" msgstr "Dienste die veraltete Bibliotheken nutzen" #. Type: multiselect #. Description #: ../needrestart.templates:2002 msgid "Which services should be restarted?" msgstr "Welche Dienste sollen neugestartet werden?" #. Type: note #. Description #. Type: note #. Description #: ../needrestart.templates:3001 ../needrestart.templates:4001 msgid "Newer kernel available" msgstr "Neuer Kernel vorhanden" #. Type: note #. Description #: ../needrestart.templates:3001 msgid "" "The currently running kernel version is ${KVERSION} and there is an ABI " "compatible upgrade pending." msgstr "Fuer die aktuelle Kernel-Version ${KVERSION} ist ein ABI-kompatibles Update vorhanden." #. Type: note #. Description #. Type: note #. Description #: ../needrestart.templates:3001 ../needrestart.templates:4001 msgid "" "Restarting the system to load the new kernel will not be handled " "automatically, so you should consider rebooting." msgstr "Das System wird nicht automatisch neugestartet um den neuen Kernel zu laden. Ein Neustart sollte durchgefuehrt werden." #. Type: note #. Description #: ../needrestart.templates:4001 msgid "" "The currently running kernel version is ${KVERSION} which is not the " "expected kernel version ${EVERSION}." msgstr "Die aktuelle Kernel-Version ist ${KVERSION}, es wird jedoch die Version ${EVERSION} erwartet." #. Type: title #. Description #: ../needrestart.templates:5001 msgid "Pending kernel upgrade" msgstr "Ausstehendes Kernel-Upgrade" needrestart-2.6/ex/debconf/po/templates.pot000066400000000000000000000033011266116133600210570ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-09-11 21:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #. Type: title #. Description #: ../needrestart.templates:1001 msgid "Daemons using outdated libraries" msgstr "" #. Type: multiselect #. Description #: ../needrestart.templates:2002 msgid "Which services should be restarted?" msgstr "" #. Type: note #. Description #. Type: note #. Description #: ../needrestart.templates:3001 ../needrestart.templates:4001 msgid "Newer kernel available" msgstr "" #. Type: note #. Description #: ../needrestart.templates:3001 msgid "" "The currently running kernel version is ${KVERSION} and there is an ABI " "compatible upgrade pending." msgstr "" #. Type: note #. Description #. Type: note #. Description #: ../needrestart.templates:3001 ../needrestart.templates:4001 msgid "" "Restarting the system to load the new kernel will not be handled " "automatically, so you should consider rebooting." msgstr "" #. Type: note #. Description #: ../needrestart.templates:4001 msgid "" "The currently running kernel version is ${KVERSION} which is not the " "expected kernel version ${EVERSION}." msgstr "" #. Type: title #. Description #: ../needrestart.templates:5001 msgid "Pending kernel upgrade" msgstr "" needrestart-2.6/ex/nagios/000077500000000000000000000000001266116133600156025ustar00rootroot00000000000000needrestart-2.6/ex/nagios/check_needrestart000077500000000000000000000010071266116133600212030ustar00rootroot00000000000000#!/bin/sh # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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. # exec sudo -n -- /usr/sbin/needrestart -p needrestart-2.6/ex/nagios/needrestart-nagios000066400000000000000000000004241266116133600213230ustar00rootroot00000000000000# needrestart nagios plugin sudoers.d config file # ----------------------------------------------- # # Please consider a look at /etc/sudoers.d/README howto enable this file. # # Allow nagios to execute the needrestart command nagios ALL=NOPASSWD: /usr/sbin/needrestart -p needrestart-2.6/ex/nagios/plugin.conf000066400000000000000000000005671266116133600177570ustar00rootroot00000000000000## remember: check_needrestart is a local check only define command { command_name check_needrestart command_line /usr/lib/nagios/plugins/check_needrestart } ## example service #define service { # host_name localhost # service_description NEEDRESTART # check_command check_needrestart # use generic-service #} needrestart-2.6/ex/needrestart.conf000066400000000000000000000063731266116133600175220ustar00rootroot00000000000000 # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 is the configuration file of needrestart. This is perl syntax. # needrstart uses reasonable default values, you might not need to # change anything. # Verbosity: # 0 => quiet # 1 => normal (default) # 2 => verbose #$nrconf{verbosity} = 2; # Path of the package manager hook scripts. #$nrconf{hook_d} = '/etc/needrestart/hook.d'; # Path of user notification scripts. #$nrconf{notify_d} = '/etc/needrestart/notify.d'; # Disable sending notifications to user sessions running obsolete binaries # using scripts from $nrconf{notify_d}. #$nrconf{sendnotify} = 0; # Restart services (l)ist only, (i)nteractive or (a)utomatically. #$nrconf{restart} = 'i'; # Use prefered UI package. #$nrconf{ui} = 'NeedRestart::UI::stdio'; # Change default answer to 'no' in (i)nteractive mode. #$nrconf{defno} = 1; # Blacklist binaries (list of regex). $nrconf{blacklist} = [ # ignore sudo (not a daemon) q(^/usr/bin/sudo(\.dpkg-new)?$), # ignore DHCP clients q(^/sbin/(dhclient|dhcpcd5|pump|udhcpc)(\.dpkg-new)?$), # ignore apt-get (Debian Bug#784237) q(^/usr/bin/apt-get(\.dpkg-new)?$), ]; # Blacklist services (list of regex) - USE WITH CARE. # You should prefere to put services to $nrconf{override_rc} instead. # Any service listed in $nrconf{blacklist_rc} we be ignored completely! #$nrconf{blacklist_rc} = [ #]; # Override service default selection (hash of regex). $nrconf{override_rc} = { # DBus q(^dbus) => 0, # display managers q(^gdm) => 0, q(^kdm) => 0, q(^nodm) => 0, q(^sddm) => 0, q(^wdm) => 0, q(^xdm) => 0, q(^lightdm) => 0, # networking stuff q(^network-manager) => 0, q(^NetworkManager) => 0, q(^wpa_supplicant) => 0, q(^openvpn) => 0, q(^quagga) => 0, q(^tinc) => 0, # gettys q(^getty@.+\.service) => 0, # systemd --user q(^user@\d+\.service) => 0, # misc q(^zfs-fuse) => 0, q(^mythtv-backend) => 0, # workaround for broken systemd-journald # (see also Debian Bug#771122 & #771254) q(^systemd-journald) => 0, # more systemd stuff # (see also Debian Bug#784238 & #784437) q(^emergency\.service$) => 0, q(^rescue\.service$) => 0, # don't restart systemd-logind, see #798097 q(^systemd-logind) => 0, }; # Disable interpreter scanners. #$nrconf{interpscan} = 0; # Enable/disable hints on pending kernel upgrades: # 1: requires the user to acknowledge pending kernels # 0: disable kernel checks completely # -1: print kernel hints to stderr only #$nrconf{kernelhints} = -1; # Read additional config snippets. if(-d q(/etc/needrestart/conf.d)) { foreach my $fn (sort ) { print STDERR "$LOGPREF eval $fn\n" if($nrconf{verbose}); eval do { local(@ARGV, $/) = $fn; <>}; die "Error parsing $fn: $@" if($@); } } needrestart-2.6/ex/notify.d/000077500000000000000000000000001266116133600160545ustar00rootroot00000000000000needrestart-2.6/ex/notify.d/200-write000077500000000000000000000016601266116133600174360ustar00rootroot00000000000000#!/bin/sh # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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. # # Use write to notify users on TTYs. case "$NR_SESSION" in /dev/tty*|/dev/pts*) echo "[$0] notify user $NR_USERNAME on $NR_SESSION" 1>&2 { echo echo "Your session is running obsolete binaries or libraries as listed below." echo "Please consider a relogin or restart of the affected processes!" echo cat echo } | write "$NR_USERNAME" "$NR_SESSION" 2> /dev/null ;; *) echo "[$0] skip session w/o tty" 1>&2 exit 1; ;; esac needrestart-2.6/ex/notify.d/400-notify-send000077500000000000000000000026271266116133600205510ustar00rootroot00000000000000#!/bin/sh # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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. # # Use notify-send (from libnotify-bin) to notify a user session via dbus. NSEND='/usr/bin/notify-send' test -x "$NSEND" || exit 1 case "$NR_SESSION" in session*) # cleanup environment unset DBUS_SESSION_BUS_ADDRESS export DISPLAY=$(sed -z -n s/DISPLAY=//p "/proc/$NR_SESSPPID/environ") export XAUTHORITY=$(sed -z -n s/XAUTHORITY=//p "/proc/$NR_SESSPPID/environ") if [ -z "$DISPLAY" ]; then echo "[$0] could not find DISPLAY for $NR_USERNAME on $NR_SESSION" 1>&2 exit 1 fi echo "[$0] notify user $NR_USERNAME on $DISPLAY" 1>&2 MSGTITLE='Relogin or restarts required!' MSGBODY="Your session is running obsolete binaries or libraries as listed below.\nPlease consider a relogin or restart of the affected processes!\n\n$(cat)" su -p -s /bin/sh -c "$NSEND -u critical -i dialog-warning \"$MSGTITLE\" \"$MSGBODY\"" "$NR_USERNAME" ;; *) echo "[$0] skip session '$NR_SESSION'" 1>&2 exit 1; ;; esac needrestart-2.6/ex/notify.d/600-mail000077500000000000000000000022131266116133600172250ustar00rootroot00000000000000#!/bin/sh # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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. # # Use /usr/bin/mail to notify a user via e-mail. MAILX='/usr/bin/mail' test -x "$MAILX" || exit 1 # Skip system users NR_USERID=`id -u "$NR_USERNAME"` if [ "0$NR_USERID" -gt 0 -a "0$NR_USERID" -lt 1000 ]; then echo "[$0] do not notify system-user $NR_USERNAME via mail" 1>&2 exit 1 fi echo "[$0] notify user $NR_USERNAME on $NR_SESSION via mail" 1>&2 { echo "Your session on host $(hostname -f) ($NR_SESSION) is running obsolete binaries or libraries as listed below." echo echo "Please consider a relogin or restart of the affected processes!" echo cat } | fold -s -w 72 | "$MAILX" -s "Relogin or restarts on host $(hostname) required!" "$NR_USERNAME" needrestart-2.6/ex/notify.d/README.needrestart000066400000000000000000000014201266116133600212500ustar00rootroot00000000000000Files located in /etc/needrestart/notify.d are used to notify running user sessions about usage of outdated libraries. needrestart runs any executable file (except *~, *.dpkg-*, *.ex) naturally sorted by the filename for each notification. If the result code is 0 than needrestart will stop to run the remaining notification binaries. The following environment variables are set: - NR_SESSION Session identifier (tty device node or systemd's session name). - NR_SESSPPID The first pid in the session detected by needrestart. - NR_UID User ID of the session owner. - NR_USERNAME Username of the session owner. The following file descriptors are used: - /dev/stdin The list of obsolete processes. - /dev/stdout Closed. - /dev/stderr Available in verbose mode (-v). needrestart-2.6/ex/polkit/000077500000000000000000000000001266116133600156245ustar00rootroot00000000000000needrestart-2.6/ex/polkit/net.fiasko-nw.needrestart.policy000066400000000000000000000013421266116133600240470ustar00rootroot00000000000000 Authentication is required to run needrestart as root view-refresh auth_admin auth_admin auth_admin /usr/sbin/needrestart true needrestart-2.6/hooks/000077500000000000000000000000001266116133600150315ustar00rootroot00000000000000needrestart-2.6/hooks/10-dpkg000077500000000000000000000041231266116133600161220ustar00rootroot00000000000000#!/usr/bin/perl # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # This DPKG hook tries to find the run-level scripts of the package's binary # which has old libraries in use. Some logic is taken from the checkrestart # (part of the debian-goodies package) package by Matt Zimmerman , # Javier Fernandez-Sanguino et. al. use Getopt::Std; use strict; use warnings; system("type dpkg-query 1> /dev/null 2> /dev/null"); exit 0 if ($? != -1 && $? >> 8); our $opt_v; getopts('v'); sub fork_pipe(@) { my $pid = open(HPIPE, '-|'); defined($pid) || die "Can't fork: $!\n"; if($pid == 0) { close(STDIN); close(STDERR) unless($opt_v); exec(@_); exit; } \*HPIPE } my $FN = shift || die "Usage: $0 \n"; my $psearch = fork_pipe(qw(dpkg-query --search), $FN); my @pkgs; while(<$psearch>) { chomp; next if(/^local diversion/); next unless(/:/); next unless(/([^:]+): $FN$/); push(@pkgs, $1); } close($psearch); exit(0) unless($#pkgs > -1); foreach my $pkg (@pkgs) { print "PACKAGE|$pkg\n"; my $plist = fork_pipe(qw(dpkg-query --listfiles), $pkg); while(<$plist>) { print "RC|$1\n" if(m@^/etc/init.d/(.+)$@); } close($plist); } exit(1); needrestart-2.6/hooks/20-rpm000077500000000000000000000036061266116133600160010ustar00rootroot00000000000000#!/usr/bin/perl # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # This RPM hook tries to find the run-level scripts of the package's binary # which has old libraries in use. use Getopt::Std; use strict; use warnings; system("type rpmquery 1> /dev/null 2> /dev/null"); exit 0 if ($? != -1 && $? >> 8); our $opt_v; getopts('c:v'); sub fork_pipe(@) { my $pid = open(HPIPE, '-|'); defined($pid) || die "Can't fork: $!\n"; if($pid == 0) { close(STDIN); close(STDERR) unless($opt_v); exec(@_); exit; } \*HPIPE } my $FN = shift || die "Usage: $0 \n"; my $psearch = fork_pipe(qw(rpmquery --file), $FN); my @pkgs; while(<$psearch>) { chomp; next if(/^file .+ is not owned by any package/); push(@pkgs, $_); } close($psearch); exit(0) unless($#pkgs > -1); foreach my $pkg (@pkgs) { print "PACKAGE|$pkg\n"; my $plist = fork_pipe(qw(rpmquery --filesbypkg), $pkg); while(<$plist>) { print "RC|$2\n" if(m@^\S+\s+/etc(/rc\.d)?/init\.d/(.+)$@); } close($plist); } exit(1); needrestart-2.6/hooks/30-pacman000077500000000000000000000034741266116133600164460ustar00rootroot00000000000000#!/usr/bin/perl # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # This PacMan hook tries to find the run-level scripts of the package's binary # which has old libraries in use. use Getopt::Std; use strict; use warnings; system("type pacman 1> /dev/null 2> /dev/null"); exit 0 if ($? != -1 && $? >> 8); our $opt_v; getopts('c:v'); sub fork_pipe(@) { my $pid = open(HPIPE, '-|'); defined($pid) || die "Can't fork: $!\n"; if($pid == 0) { close(STDIN); close(STDERR) unless($opt_v); exec(@_); exit; } \*HPIPE } my $FN = shift || die "Usage: $0 \n"; my $psearch = fork_pipe(qw(pacman -Qqo), $FN); my @pkgs; while(<$psearch>) { chomp; push(@pkgs, $_); } close($psearch); exit(0) unless($#pkgs > -1); foreach my $pkg (@pkgs) { print "PACKAGE|$pkg\n"; my $plist = fork_pipe(qw(pacman -Qql), $pkg); while(<$plist>) { print "RC|$2\n" if(m@/etc(/rc\.d)?/init\.d/(.+)$@); } close($plist); } exit(1); needrestart-2.6/hooks/90-none000077500000000000000000000030661266116133600161510ustar00rootroot00000000000000#!/usr/bin/perl # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # This fallback hook tries the guess the rc script name from the binary name. # It might work with programs which are not installed via an (supported) # package manager like dpkg or rpm. use Getopt::Std; use strict; use warnings; our $opt_v; getopts('c:v'); sub check_rc($) { my $bn = shift; my $rc = "/etc/init.d/$bn"; return ($bn) if(-x $rc); return (); } my $FN = shift || die "Usage: $0 \n"; $FN =~ m@/(([^/]+)d?)$@; my @rc; push(@rc, check_rc($1)); push(@rc, check_rc($2)) if($1 ne $2); exit(0) unless($#rc > -1); foreach my $rc (@rc) { print "PACKAGE|$rc\n"; print "RC|$rc\n"; } exit(1); needrestart-2.6/lib/000077500000000000000000000000001266116133600144545ustar00rootroot00000000000000needrestart-2.6/lib/vmlinuz-get-version000077500000000000000000000035641266116133600203560ustar00rootroot00000000000000#!/bin/sh # ---------------------------------------------------------------------- # This file was taken from the Linux kernel source tree (scripts/extract-vmlinux) # and has been adopted for the use within needrestart. # # extract-vmlinux - Extract uncompressed vmlinux from a kernel image # # Inspired from extract-ikconfig # (c) 2009,2010 Dick Streefland # # (c) 2011 Corentin Chary # # Adopted for needrestart # (c) 2016 Thomas Liske # # Licensed under the GNU General Public License, version 2 (GPLv2). # ---------------------------------------------------------------------- get_version() { # search and output version string pattern strings "$1" | grep -m 1 '^Linux version ' && exit 0 } try_decompress() { # The obscure use of the "tr" filter is to work around older versions of # "grep" that report the byte offset of the line instead of the pattern. # Try to find the header ($1) and decompress from here for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` do pos=${pos%%:*} tail -c+$pos "$img" | $3 > $tmp 2> /dev/null get_version $tmp done } # Check invocation: me=${0##*/} img=$1 if [ $# -lt 1 -o $# -gt 2 -o ! -s "$img" ] then echo "Usage: $me [debug]" >&2 exit 2 fi if [ "$2" = "1" ]; then set -x fi # Prepare temp files: tmp=$(mktemp) trap "rm -f $tmp" 0 # Initial attempt for uncompressed images or objects: get_version $img # That didn't work, so retry after decompression. which gunzip > /dev/null && try_decompress '\037\213\010' xy gunzip which unxz > /dev/null && try_decompress '\3757zXZ\000' abcde unxz which bunzip2 > /dev/null && try_decompress 'BZh' xy bunzip2 which unlzma > /dev/null && try_decompress '\135\0\0\0' xxx unlzma which lzop > /dev/null && try_decompress '\211\114\132' xy 'lzop -d' needrestart-2.6/man/000077500000000000000000000000001266116133600144615ustar00rootroot00000000000000needrestart-2.6/man/needrestart.1000066400000000000000000000025011266116133600170610ustar00rootroot00000000000000.TH NEEDRESTART "1" "January 2015" "needrestart " "User Commands" .SH NAME needrestart \- needrestart .SH DESCRIPTION needrestart checks which daemons need to be restarted after library upgrades. .SH USAGE Usage: .IP needrestart [\-(v|q)] [\-n] [\-c ] [\-r ] [\-f ] [\-(b|p)] [\-kl] .TP \fB\-v\fR be more verbose .TP \fB\-q\fR be quiet .TP \fB\-n\fR set default answer to 'no' .TP \fB\-c\fR config filename .TP \fB\-r\fR set restart mode .TP l (l)ist only .TP i (i)nteractive restart .TP a (a)utomatically restart .TP \fB\-b\fR enable batch mode .TP \fB\-p\fR nagios plugin mode: makes output and exit codes nagios compatible .TP \fB\-f\fR overwrite debconf(7) frontend, sets the DEBIAN_FRONT environment variable to .PP By using one of the following options only the specified checks are performed: .TP \fB\-k\fR check for obsolete kernel .TP \fB\-l\fR check for obsolete libraries .SH "AUTHOR" Thomas Liske .SH "COPYRIGHT" 2013 - 2015 (C) Thomas Liske [http://fiasko\-nw.net/~thomas/] .PP 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. .SH "UPSTREAM" https://github.com/liske/needrestart needrestart-2.6/needrestart000077500000000000000000000572211266116133600161630ustar00rootroot00000000000000#!/usr/bin/perl # nagios: -epn # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2016 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # use Cwd qw(realpath); use Getopt::Std; use NeedRestart; use NeedRestart::UI; use NeedRestart::Interp; use NeedRestart::Kernel; use NeedRestart::Utils; use Sort::Naturally; use warnings; use strict; $|++; $Getopt::Std::STANDARD_HELP_VERSION++; my $LOGPREF = '[main]'; my $is_systemd = -d qq(/run/systemd/system); my $is_tty = (-t *STDERR || -t *STDOUT || -t *STDIN); sub HELP_MESSAGE { print <] [-r ] [-f ] [-bkl] -v be more verbose -q be quiet -n set default answer to 'no' -c config filename -r set restart mode l (l)ist only i (i)nteractive restart a (a)utomatically restart -b enable batch mode -p enable nagios plugin mode -f overwrite debconf frontend By using the following options only the specified checks are performed: -k check for obsolete kernel -l check for obsolete libraries --help show this help --version show version information USG } sub VERSION_MESSAGE { print < Copyright Holder: 2013 - 2016 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] Upstream: https://github.com/liske/needrestart 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. LIC #/ } our %nrconf = ( verbosity => 1, hook_d => '/etc/needrestart/hook.d', notify_d => '/etc/needrestart/notify.d', sendnotify => 1, restart => 'i', defno => 0, blacklist => [], blacklist_rc => [], override_rc => [], interpscan => 1, kernelhints => 1, ); # backup ARGV (required for Debconf) my @argv = @ARGV; our $opt_c = '/etc/needrestart/needrestart.conf'; our $opt_v; our $opt_r; our $opt_n; our $opt_b; our $opt_f; our $opt_k; our $opt_l; our $opt_p; our $opt_q; unless(getopts('c:vr:nbf:klpq')) { HELP_MESSAGE; exit 1; } # restore ARGV @ARGV = @argv; die "ERROR: Could not read config file '$opt_c'!\n" unless(-r $opt_c || $opt_b); # overwrite debconf frontend $ENV{DEBIAN_FRONTEND} = $opt_f if($opt_f); # be quiet if($opt_q) { $nrconf{verbosity} = 0; } # be verbose elsif($opt_v) { $nrconf{verbosity} = 2; } # slurp config file print STDERR "$LOGPREF eval $opt_c\n" if($nrconf{verbosity} > 1); eval do { local(@ARGV, $/) = $opt_c; <>}; die "Error parsing $opt_c: $@" if($@); # fallback to stdio on verbose mode $nrconf{ui} = qq(NeedRestart::UI::stdio) if($nrconf{verbosity} > 1); die "Hook directory '$nrconf{hook_d}' is invalid!\n" unless(-d $nrconf{hook_d} || $opt_b); $opt_r = $nrconf{restart} unless(defined($opt_r)); die "ERROR: Unknown restart option '$opt_r'!\n" unless($opt_r =~ /^(l|i|a)$/); $is_tty++ if($opt_r eq 'i' && exists($ENV{DEBIAN_FRONTEND}) && $ENV{DEBIAN_FRONTEND} eq 'noninteractive'); $opt_r = 'l' if(!$is_tty && $opt_r eq 'i'); $nrconf{defno}++ if($opt_n); $opt_b++ if($opt_p); # running mode (user or root) my $uid = $<; if($uid) { if($opt_p) { print STDERR "UNKN - This plugin needs to be run as root!\n"; exit 3; } print STDERR "$LOGPREF running in user-mode\n" if($nrconf{verbosity} > 1); } else { print STDERR "$LOGPREF running in root-mode\n" if($nrconf{verbosity} > 1); } # get current runlevel, fallback to '2' my $runlevel = `who -r` || ''; chomp($runlevel); $runlevel = 2 unless($runlevel =~ s/^.+run-level (\S)\s.+$/$1/); # get UI my $ui = ($opt_b ? NeedRestart::UI->new(0) : needrestart_ui($nrconf{verbosity}, ($is_tty ? $nrconf{ui} : 'NeedRestart::UI::stdio'))); die "Error: no UI class available!\n" unless(defined($ui)); # enable/disable checks unless(defined($opt_k) || defined($opt_l)) { $opt_k = ($uid ? undef : 1); $opt_l = 1; } sub parse_lsbinit($) { my $rc = '/etc/init.d/'.shift; my %lsb; open(HLSB, '<', $rc) || die "Can't open $rc: $!\n"; my $found; while(my $line = ) { unless($found) { $found++ if($line =~ /^### BEGIN INIT INFO/); next; } elsif($line =~ /^### END INIT INFO/) { last; } chomp($line); $lsb{lc($1)} = $2 if($line =~ /^# ([^:]+):\s+(.+)$/); } unless($found) { print STDERR "WARNING: $rc has no LSB tags!\n" unless(%lsb); return undef; } # pid file heuristic $found = 0; my %pidfiles; while(my $line = ) { if($line =~ m@(\S*/run/[^/]+.pid)@ && -r $1) { $pidfiles{$1}++; $found++; } } $lsb{pidfiles} = [keys %pidfiles] if($found); close(HLSB); return %lsb; } print STDERR "$LOGPREF detected systemd\n" if($nrconf{verbosity} > 1 && $is_systemd); my @systemd_restart; sub restart_cmd($) { my $rc = shift; if($rc =~ /.+\.service$/) { push(@systemd_restart, $rc); (); } elsif($rc eq q(systemd manager)) { (qw(systemctl daemon-reexec)); } elsif($rc eq q(sysv init)) { (qw(telinit u)); } else { (q(service), $rc, q(restart)); } } # map UID to username (cached) my %uidcache; sub uid2name($) { my $uid = shift; return $uidcache{$uid} if(exists($uidcache{$uid})); return $uidcache{$uid} = getpwuid($uid) || $uid; } my %nagios = ( # kernel kstr => q(unknown), kret => 3, kperf => q(U), # services sstr => q(unknown), sret => 3, sperf => q(U), # sessions ustr => q(unknown), uret => 3, uperf => q(U), ); print "NEEDRESTART-VER: $NeedRestart::VERSION\n" if($opt_b && !$opt_p); my %restart; my %sessions; if(defined($opt_l)) { my @ign_pids=($$, getppid()); # inspect only pids my $ptable = nr_ptable(); # find session parent sub findppid($@) { my $uid = shift; my ($pid, @pids) = @_; if($ptable->{$pid}->{ppid} == 1) { return $pid if($ptable->{$pid}->{uid} == $uid); return undef; } foreach my $pid (@pids) { my $ppid = &findppid($uid, $pid); return $ppid if($ppid); } return $pid; } $ui->progress_prep(scalar keys %$ptable, 'Scanning processes...'); my %stage2; for my $pid (sort {$a <=> $b} keys %$ptable) { $ui->progress_step; # user-mode: skip foreign processes next if($uid && $ptable->{$pid}->{uid} != $uid); # skip myself next if(grep {$pid == $_} @ign_pids); my $restart = 0; my $exe = nr_readlink($pid); # ignore kernel threads next unless(defined($exe)); # orphaned binary $restart++ if (defined($exe) && $exe =~ s/ \(deleted\)$//); # Linux $restart++ if (defined($exe) && $exe =~ s/^\(deleted\)//); # Linux VServer print STDERR "$LOGPREF #$pid uses obsolete binary $exe\n" if($restart && $nrconf{verbosity} > 1); # ignore blacklisted binaries next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}}); # read file mappings (Linux 2.0+) unless($restart) { open(HMAP, '<', "/proc/$pid/maps") || next; while() { chomp; my ($maddr, $mperm, $moffset, $mdev, $minode, $path) = split(/\s+/, $_, 6); # skip special handles and non-executable mappings next unless(defined($path) && $minode != 0 && $path ne '' && $mperm =~ /x/); # skip special device paths next if($path =~ m@^/(SYSV00000000$|drm$|dev/)@); # skip aio(7) mapping next if($path =~ m@^/\[aio\]@); # skip Oil Runtime Compiler's JIT files next if($path =~ m@^/orcexec\.[\w\d]+$@); # check for non-existing libs unless(-e "/proc/$pid/root/$path" || -e $path) { unless($path =~ m@^/tmp/@ || $path =~ m@^(/var)?/run/@) { print STDERR "$LOGPREF #$pid uses non-existing $path\n" if($nrconf{verbosity} > 1); $restart++; last; } } # get on-disk info my @stats; my ($sdev, $sinode) = stat("/proc/$pid/root/$path"); push(@stats, [$sdev, $sinode]) if(defined($sinode)); ($sdev, $sinode) = stat($path); push(@stats, [$sdev, $sinode]) if(defined($sinode)); last unless(scalar @stats); my $found = 0; foreach my $stat (@stats) { ($sdev, $sinode) = @$stat; my @sdevs = ( # glibc gnu_dev_* definition from sysmacros.h sprintf("%02x:%02x", (($sdev >> 8) & 0xfff) | (($sdev >> 32) & ~0xfff), (($sdev & 0xff) | (($sdev >> 12) & ~0xff))), # Traditional definition of major(3) and minor(3) sprintf("%02x:%02x", $sdev >> 8, $sdev & 0xff), # kFreeBSD: /proc//maps does not contain device IDs qq(00:00) ); # compare maps content vs. on-disk if($minode eq $sinode && ((grep {$mdev eq $_} @sdevs) || # BTRFS breaks device ID mapping completely... # ignoring unnamed device IDs for now $mdev =~ /^00:/)) { $found++; last; } } unless($found) { print STDERR "$LOGPREF #$pid uses obsolete $path\n" if($nrconf{verbosity} > 1); $restart++; last; } } close(HMAP); } unless($restart || !$nrconf{interpscan}) { $restart++ if(needrestart_interp_check($nrconf{verbosity} > 1, $pid, $exe)); } # handle containers (LXC, docker, etc.) next if($restart && needrestart_cont_check($nrconf{verbosity} > 1, $pid, $exe)); # restart needed? next unless($restart); # handle user sessions if($ptable->{$pid}->{ttydev} ne '') { my $ttydev = realpath( $ptable->{$pid}->{ttydev} ); print STDERR "$LOGPREF #$pid part of user session: uid=$ptable->{$pid}->{uid} sess=$ttydev\n" if($nrconf{verbosity} > 1); push(@{ $sessions{ $ptable->{$pid}->{uid} }->{ $ttydev }->{ $ptable->{$pid}->{fname} } }, $pid); # add session processes to stage2 only in user mode $stage2{$pid} = $exe if($uid); next; } # find parent process my $ppid = $ptable->{$pid}->{ppid}; if($ppid != $pid && $ppid > 1 && !$uid) { print STDERR "$LOGPREF #$pid is a child of #$ppid\n" if($nrconf{verbosity} > 1); if($uid && $ptable->{$ppid}->{uid} != $uid) { print STDERR "$LOGPREF #$ppid is a foreign process\n" if($nrconf{verbosity} > 1); $stage2{$pid} = $exe; } else { unless(exists($stage2{$ppid})) { my $pexe = nr_readlink($ppid); # ignore kernel threads next unless(defined($pexe)); $stage2{$ppid} = $pexe; } } } else { print STDERR "$LOGPREF #$pid is not a child\n" if($nrconf{verbosity} > 1 && !$uid); $stage2{$pid} = $exe; } } $ui->progress_fin; if(scalar keys %stage2 && !$uid) { $ui->progress_prep(scalar keys %stage2, 'Scanning candidates...'); foreach my $pid (sort {$a <=> $b} keys %stage2) { $ui->progress_step; # skip myself next if(grep {$pid == $_} @ign_pids); my $exe = nr_readlink($pid); $exe =~ s/ \(deleted\)$//; # Linux $exe =~ s/^\(deleted\)//; # Linux VServer print STDERR "$LOGPREF #$pid exe => $exe\n" if($nrconf{verbosity} > 1); # try to find interpreter source file ($exe) = (needrestart_interp_source($nrconf{verbosity} > 1, $pid, $exe), $exe); # ignore blacklisted binaries next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}}); if($is_systemd) { # systemd manager if($pid == 1 && $exe =~ m@^/lib/systemd/systemd@) { print STDERR "$LOGPREF #$pid is systemd manager\n" if($nrconf{verbosity} > 1); $restart{q(systemd manager)}++; next; } # get unit name from /proc//cgroup if(open(HCGROUP, qq(/proc/$pid/cgroup))) { my ($rc) = map { chomp; my ($id, $type, $value) = split(/:/); if($type ne q(name=systemd)) { (); } else { if($value = m@/user-(\d+)\.slice/session-(\d+)\.scope@) { print STDERR "$LOGPREF #$pid part of user session: uid=$1 sess=$2\n" if($nrconf{verbosity} > 1); push(@{ $sessions{$1}->{"session #$2"}->{ $ptable->{$pid}->{fname} } }, $pid); next; } if($value = m@/user\@(\d+)\.service@) { print STDERR "$LOGPREF #$pid part of user service: uid=$1\n" if($nrconf{verbosity} > 1); push(@{ $sessions{$1}->{"session services"}->{ $ptable->{$pid}->{fname} } }, $pid); next; } elsif($value =~ m@/([^/]+\.service)$@) { ($1); } else { print STDERR "$LOGPREF #$pid unexpected cgroup '$value'\n" if($nrconf{verbosity} > 1); (); } } } ; close(HCGROUP); if($rc) { print STDERR "$LOGPREF #$pid is $rc\n" if($nrconf{verbosity} > 1); $restart{$rc}++; next; } } # did not get the unit name, yet - try systemctl status print STDERR "$LOGPREF /proc/#$pid/cgroup: $! - trying systemctl status\n" if($nrconf{verbosity} > 1 && $!); my $systemctl = nr_fork_pipe($nrconf{verbosity} > 1, qq(systemctl), qq(-n), qq(0), qq(--full), qq(status), $pid); my $ret = <$systemctl>; close($systemctl); if(defined($ret) && $ret =~ /([^.\s]+\.service) /) { my $s = $1; print STDERR "$LOGPREF #$pid is $s\n" if($nrconf{verbosity} > 1); $restart{$s}++; $s =~ s/\.service$//; delete($restart{$s}); next; } } else { # sysv init if($pid == 1 && $exe =~ m@^/sbin/init@) { print STDERR "$LOGPREF #$pid is sysv init\n" if($nrconf{verbosity} > 1); $restart{q(sysv init)}++; next; } } my $pkg; foreach my $hook (nsort <$nrconf{hook_d}/*>) { print STDERR "$LOGPREF #$pid running $hook\n" if($nrconf{verbosity} > 1); my $found = 0; my $prun = nr_fork_pipe($nrconf{verbosity} > 1, $hook, ($nrconf{verbosity} > 1 ? qw(-v) : ()), $exe); my @nopids; while(<$prun>) { chomp; my @v = split(/\|/); if($v[0] eq 'PACKAGE' && $v[1]) { $pkg = $v[1]; print STDERR "$LOGPREF #$pid package: $v[1]\n" if($nrconf{verbosity} > 1); next; } if($v[0] eq 'RC') { my %lsb = parse_lsbinit($v[1]); unless(%lsb && exists($lsb{'default-start'})) { # If the script has no LSB tags we consider to call it later - they # are broken anyway. print STDERR "$LOGPREF no LSB headers found at $v[1]\n" if($nrconf{verbosity} > 1); push(@nopids, $v[1]); } # In the run-levels S and 1 no daemons are being started (normaly). # We don't call any rc.d script not started in the current run-level. elsif($lsb{'default-start'} =~ /$runlevel/) { # If a pidfile has been found, try to look for the daemon and ignore # any forked/detached childs (just a heuristic due Debian Bug#721810). if(exists($lsb{pidfiles})) { foreach my $pidfile (@{ $lsb{pidfiles} }) { open(HPID, '<', "$pidfile") || next; my $p = ; close(HPID); if(int($p) == $pid) { print STDERR "$LOGPREF #$pid has been started by $v[1] - triggering\n" if($nrconf{verbosity} > 1); $restart{$v[1]}++; $found++; last; } } } else { print STDERR "$LOGPREF no pidfile reference found at $v[1]\n" if($nrconf{verbosity} > 1); push(@nopids, $v[1]); } } else { print STDERR "$LOGPREF #$pid rc.d script $v[1] should not start in the current run-level($runlevel)\n" if($nrconf{verbosity} > 1); } } } # No perfect hit - call any rc scripts instead. if(!$found && $#nopids > -1) { foreach my $rc (@nopids) { if($is_systemd && exists($restart{"$rc.service"})) { print STDERR "$LOGPREF #$pid rc.d script $rc seems to be superseeded by $rc.service\n" if($nrconf{verbosity} > 1); } else { $restart{$rc}++; } } $found++; } last if($found); } } $ui->progress_fin; } # List user's processes in user-mode if($uid && scalar %stage2) { my %fnames; foreach my $pid (keys %stage2) { push(@{$fnames{ $ptable->{$pid}->{fname} }}, $pid); } if($opt_b) { print map { "NEEDRESTART-PID: $_=".join(',', @{ $fnames{$_} })."\n"; } nsort keys %fnames; } else { $ui->notice('Your outdated processes:'); $ui->notice(join(', ',map { $_.'['.join(', ', @{ $fnames{$_} }).']'; } nsort keys %fnames)); } } } # Apply rc/service blacklist foreach my $rc (keys %restart) { next unless(scalar grep { $rc =~ /$_/; } @{$nrconf{blacklist_rc}}); print STDERR "$LOGPREF $rc is blacklisted -> ignored\n" if($nrconf{verbosity} > 1); delete($restart{$rc}); } # Skip kernel stuff within containers if(needrestart_cont_check($nrconf{verbosity} > 1, 1, nr_readlink(1), 1)) { print STDERR "$LOGPREF container detected, skipping kernel check\n" if($nrconf{verbosity} > 1); $opt_k = undef; } if(defined($opt_k)) { my ($kresult, %kvars) = ($nrconf{kernelhints} || $opt_b ? nr_kernel_check($nrconf{verbosity} > 1, $ui) : ()); if(defined($kresult)) { if($opt_b) { unless($opt_p) { print "NEEDRESTART-KCUR: $kvars{KVERSION}\n"; print "NEEDRESTART-KEXP: $kvars{EVERSION}\n" if(defined($kvars{EVERSION})); print "NEEDRESTART-KSTA: $kresult\n"; } else { $nagios{kstr} = $kvars{KVERSION}; if($kresult == NRK_VERUPGRADE) { $nagios{kstr} .= "!=$kvars{EVERSION} (!)"; $nagios{kret} = 1; $nagios{kperf} = 2; } elsif($kresult == NRK_ABIUPGRADE) { $nagios{kstr} .= " (!)"; $nagios{kret} = 1; $nagios{kperf} = 1; } elsif($kresult == NRK_NOUPGRADE) { $nagios{kret} = 0; $nagios{kperf} = 0; } } } else { if($kresult == NRK_NOUPGRADE) { $ui->notice(($kvars{ABIDETECT} ? 'Running kernel seems to be up-to-date.' : "Running kernel seems to be up-to-date (ABI upgrades are not detected).")); } elsif($kresult == NRK_ABIUPGRADE) { if($nrconf{kernelhints} < 0) { $ui->notice( "The currently running kernel version is $kvars{KVERSION} and there is an ABI compatible upgrade pending." ); } else { $ui->announce_abi(%kvars); } } elsif($kresult == NRK_VERUPGRADE) { if($nrconf{kernelhints} < 0) { $ui->notice( "The currently running kernel version is $kvars{KVERSION} which is not the expected kernel version $kvars{EVERSION}." ); } else { $ui->announce_ver(%kvars); } } else { $ui->notice('Failed to retrieve available kernel versions.'); } } } } if(defined($opt_l) && !$uid) { ## SERVICES unless(scalar %restart) { $ui->notice('No services need to be restarted.') unless($opt_b); if($opt_p) { $nagios{sstr} = q(none); $nagios{sret} = 0; $nagios{sperf} = 0; } } else { if($opt_b || $opt_r ne 'i') { $ui->notice('Services to be restarted:'); if($opt_p) { $nagios{sstr} = (scalar keys %restart).' (!)'; $nagios{sret} = 2; $nagios{sperf} = (scalar keys %restart); } foreach my $rc (sort { lc($a) cmp lc($b) } keys %restart) { if($opt_b) { print "NEEDRESTART-SVC: $rc\n" unless($opt_p); next; } # don't restart greylisted services... my $restart = !$nrconf{defno}; foreach my $re (keys %{$nrconf{override_rc}}) { next unless($rc =~ /$re/); $restart = $nrconf{override_rc}->{$re}; last; } # ...but complain about them unless($restart) { $ui->notice("Skipping $rc..."); next; } my @cmd = restart_cmd($rc); next unless($#cmd > -1); if($opt_r eq 'a') { system(@cmd); } else { $ui->notice(join(' ', @cmd)); } } unless($opt_b || $#systemd_restart == -1) { my @cmd = (qq(systemctl), qq(restart), @systemd_restart); if($opt_r eq 'a') { $ui->notice('Restarting services using systemd...'); system(@cmd); } else { $ui->notice(join(' ', @cmd)); } } } else { my $o = 0; $ui->query_pkgs('Services to be restarted:', $nrconf{defno}, \%restart, $nrconf{override_rc}, sub { my @cmd = restart_cmd(shift); system(@cmd) if($#cmd > -1); }); if($#systemd_restart > -1) { $ui->notice('Restarting services using systemd...'); system(qq(systemctl), qq(restart), @systemd_restart); } } } ## CONTAINERS @systemd_restart = (); my %conts = needrestart_cont_get($nrconf{verbosity} > 1); unless(scalar %conts) { $ui->notice('No containers need to be restarted.') unless($opt_b); if($opt_p) { $nagios{cstr} = q(none); $nagios{cret} = 0; $nagios{cperf} = 0; } } else { if($opt_b || $opt_r ne 'i') { $ui->notice('Containers to be restarted:'); if($opt_p) { $nagios{cstr} = (scalar keys %conts).' (!)'; $nagios{cret} = 2; $nagios{cperf} = (scalar keys %conts); } foreach my $cont (sort { lc($a) cmp lc($b) } keys %conts) { if($opt_b) { print "NEEDRESTART-CONT: $cont\n" unless($opt_p); next; } # don't restart greylisted services... my $restart = !$nrconf{defno}; foreach my $re (keys %{$nrconf{override_rc}}) { next unless($cont =~ /$re/); $restart = $nrconf{override_rc}->{$re}; last; } # ...but complain about them unless($restart) { $ui->notice("Skipping $cont..."); next; } if($opt_r eq 'a') { system(@{ $conts{$cont} }); } else { $ui->notice(join(' ', @{ $conts{$cont} })); } } } else { my $o = 0; $ui->query_conts('Containers to be restarted:', $nrconf{defno}, \%conts, $nrconf{override_rc}, sub { my $cont = shift; system(@{ $conts{$cont} }); }); } } ## SESSIONS # list and notify user sessions if(scalar keys %sessions) { $ui->notice('User sessions:'); if($opt_p) { $nagios{ustr} = (scalar keys %sessions).' (!)'; $nagios{uret} = 1; $nagios{uperf} = (scalar keys %sessions); } unless($opt_p || $opt_b) { foreach my $uid (sort { ncmp(uid2name($a), uid2name($b)); } keys %sessions) { foreach my $sess (sort keys %{ $sessions{$uid} }) { my $fnames = join(', ',map { $_.'['.join(',', @{ $sessions{$uid}->{$sess}->{$_} }).']'; } nsort keys %{ $sessions{$uid}->{$sess} }); $ui->notice(uid2name($uid)." on $sess is running obsolete $fnames"); if($nrconf{sendnotify}) { local %ENV; $ENV{NR_UID} = $uid; $ENV{NR_USERNAME} = uid2name($uid); $ENV{NR_SESSION} = $sess; $ENV{NR_SESSPPID} = findppid($uid, sort map { @$_; } values %{ $sessions{$uid}->{$sess} }); foreach my $bin (nsort <$nrconf{notify_d}/*>) { next unless(-x $bin); next if($bin =~ /(~|\.dpkg-[^.]+)$/); print STDERR "$LOGPREF run $bin\n" if($nrconf{verbosity} > 1); my $pipe = nr_fork_pipew($nrconf{verbosity} > 1, $bin); print $pipe "$fnames\n"; last if(close($pipe)); } } } } } } elsif($opt_p) { $nagios{ustr} = 'none'; $nagios{uret} = 0; $nagios{uperf} = 0; } } # nagios plugin output if($opt_p) { my %states = ( 0 => q(OK), 1 => q(WARN), 2 => q(CRIT), 3 => q(UNKN), ); my ($ret) = reverse sort (($opt_k ? $nagios{kret} : ()), ($opt_l ? ($nagios{sret}, $nagios{cret}, $nagios{uret}) : ())); print "$states{$ret} - ", join(', ', ($opt_k ? "Kernel: $nagios{kstr}" : ()), ($opt_l ? "Services: $nagios{sstr}" : ()), ($opt_l ? "Containers: $nagios{cstr}" : ()), ($opt_l ? "Sessions: $nagios{ustr}" : ()), ), '|', join(' ', ($opt_k ? "Kernel=$nagios{kperf};0;;0;2" : ()), ($opt_l ? "Services=$nagios{sperf};;0;0" : ()), ($opt_l ? "Containers=$nagios{cperf};;0;0" : ()), ($opt_l ? "Sessions=$nagios{uperf};0;;0" : ()), ), "\n"; exit $ret; } needrestart-2.6/perl/000077500000000000000000000000001266116133600146505ustar00rootroot00000000000000needrestart-2.6/perl/Makefile.PL000066400000000000000000000004521266116133600166230ustar00rootroot00000000000000use ExtUtils::MakeMaker; WriteMakefile( 'AUTHOR' => 'Thomas Liske ', 'LICENSE' => 'gpl', 'NAME' => 'NeedRestart', 'PREREQ_PM' => { Module::Find => 0, Module::ScanDeps => 0, Proc::ProcessTable => 0, Sort::Naturally => 0, Term::ReadKey => 0. }, ); needrestart-2.6/perl/lib/000077500000000000000000000000001266116133600154165ustar00rootroot00000000000000needrestart-2.6/perl/lib/NeedRestart.pm000066400000000000000000000123431266116133600201770ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2016 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart; use strict; use warnings; use Module::Find; use NeedRestart::Utils; use NeedRestart::CONT; use Sort::Naturally; use constant { NEEDRESTART_PRIO_LOW => 1, NEEDRESTART_PRIO_MEDIUM => 10, NEEDRESTART_PRIO_HIGH => 100, }; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( NEEDRESTART_PRIO_LOW NEEDRESTART_PRIO_MEDIUM NEEDRESTART_PRIO_HIGH needrestart_ui needrestart_interp_check needrestart_interp_source needrestart_cont_check needrestart_cont_get needrestart_cont_cmd ); our @EXPORT_OK = qw( needrestart_ui_register needrestart_ui_init needrestart_interp_register needrestart_cont_register ); our %EXPORT_TAGS = ( ui => [qw( NEEDRESTART_PRIO_LOW NEEDRESTART_PRIO_MEDIUM NEEDRESTART_PRIO_HIGH needrestart_ui_register needrestart_ui_init )], interp => [qw( needrestart_interp_register )], cont => [qw( needrestart_cont_register )], ); our $VERSION = '2.6'; my $LOGPREF = '[Core]'; my %UIs; sub needrestart_ui_register($$) { my $pkg = shift; my $prio = shift; $UIs{$pkg} = $prio; } sub needrestart_ui_init($$) { my $verbosity = shift; my $prefui = shift; # load prefered UI module if(defined($prefui)) { return if(eval "use $prefui; 1;"); } # autoload UI modules foreach my $module (findsubmod NeedRestart::UI) { unless(eval "use $module; 1;") { warn "Error loading $module: $@\n" if($@ && ($verbosity > 1)); } } } sub needrestart_ui { my $verbosity = shift; my $prefui = shift; needrestart_ui_init($verbosity, $prefui) unless(%UIs); my ($ui) = sort { ncmp($UIs{$b}, $UIs{$a}) } keys %UIs; return undef unless($ui); print STDERR "$LOGPREF Using UI '$ui'...\n" if($verbosity > 1); return $ui->new($verbosity); } my %Interps; my $idebug; sub needrestart_interp_register($) { my $pkg = shift; $Interps{$pkg} = new $pkg($idebug); } sub needrestart_interp_init($) { $idebug = shift; # autoload Interp modules foreach my $module (findsubmod NeedRestart::Interp) { unless(eval "use $module; 1;") { warn "Error loading $module: $@\n" if($@ && $idebug); } } } sub needrestart_interp_check($$$) { my $debug = shift; my $pid = shift; my $bin = shift; needrestart_interp_init($debug) unless(%Interps); foreach my $interp (values %Interps) { if($interp->isa($pid, $bin)) { print STDERR "$LOGPREF #$pid is a ".(ref $interp)."\n" if($debug); my $ps = nr_ptable_pid($pid); my %files = $interp->files($pid); if(grep {!defined($_) || $_ > $ps->start} values %files) { if($debug) { print STDERR "$LOGPREF #$pid uses obsolete script file(s):"; print STDERR join("\n$LOGPREF #$pid ", '', map {(!defined($files{$_}) || $files{$_} > $ps->start ? $_ : ())} keys %files); print STDERR "\n"; } return 1; } } } return 0; } sub needrestart_interp_source($$$) { my $debug = shift; my $pid = shift; my $bin = shift; needrestart_interp_init($debug) unless(%Interps); foreach my $interp (values %Interps) { if($interp->isa($pid, $bin)) { print STDERR "$LOGPREF #$pid is a ".(ref $interp)."\n" if($debug); my $src = $interp->source($pid); print STDERR "$LOGPREF #$pid source is ".(defined($src) ? $src : 'UNKNOWN')."\n" if($debug); return ($src) if(defined($src));; return (); } } return (); } my %CONT; my $ndebug; sub needrestart_cont_register($) { my $pkg = shift; $CONT{$pkg} = new $pkg($ndebug); } sub needrestart_cont_init($) { $ndebug = shift; # autoload CONT modules foreach my $module (findsubmod NeedRestart::CONT) { unless(eval "use $module; 1;") { warn "Error loading $module: $@\n" if($@ && $ndebug); } } } sub needrestart_cont_check($$$;$) { my $debug = shift; my $pid = shift; my $bin = shift; my $norestart = shift || 0; needrestart_cont_init($debug) unless(scalar keys %CONT); foreach my $cont (values %CONT) { return 1 if($cont->check($pid, $bin, $norestart)); } return 0; } sub needrestart_cont_get($) { my $debug = shift; return map { my $cont = $_; my $n = ref $cont; $n =~ s/^NeedRestart::CONT:://; my %c = $cont->get; map { ("$n $_" => $c{$_}); } sort keys %c; } sort { (ref $a) cmp (ref $b); } values %CONT; } 1; needrestart-2.6/perl/lib/NeedRestart/000077500000000000000000000000001266116133600176365ustar00rootroot00000000000000needrestart-2.6/perl/lib/NeedRestart/CONT.pm000066400000000000000000000034011266116133600207350ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::CONT; use strict; use warnings; use NeedRestart::Utils; my $LOGPREF = '[CONT]'; my $nspid = get_nspid(undef, 1); my $ptable = nr_ptable(); sub new { my $class = shift; my $debug = shift; return bless { debug => $debug, nspid => $nspid, }, $class; } sub check { my $self = shift; return 0; } sub get { my $self = shift; return (); } sub get_nspid { my $self = shift; my $pid = shift; my $stat = nr_stat(qq(/proc/$pid/ns/pid)); return $stat->{ino} if($stat); return undef; } sub find_nsparent { my $self = shift; my $pid = shift; return undef unless(exists($ptable->{$pid})); my $ns = $self->get_nspid($ptable->{$pid}->{ppid}); return $ptable->{$pid}->{ppid} if($ns && $ns == $nspid); return $self->find_nsparent($ptable->{$pid}->{ppid}); } 1; needrestart-2.6/perl/lib/NeedRestart/CONT/000077500000000000000000000000001266116133600204015ustar00rootroot00000000000000needrestart-2.6/perl/lib/NeedRestart/CONT/LXC.pm000066400000000000000000000044431266116133600213720ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::CONT::LXC; use strict; use warnings; use parent qw(NeedRestart::CONT); use NeedRestart qw(:cont); use NeedRestart::Utils; my $LOGPREF = '[LXC]'; needrestart_cont_register(__PACKAGE__) unless($<); sub new { my $class = shift; my $self = $class->SUPER::new(@_); die "Could not get NS PID of #1!\n" unless(defined($self->{nspid})); $self->{lxc} = {}; return bless $self, $class; } sub check { my $self = shift; my $pid = shift; my $bin = shift; my $norestart = shift; my $ns = $self->get_nspid($pid); # stop here if no dedicated PID namespace is used return 0 if(!$ns || $ns == $self->{nspid}); unless(open(FCG, qq(/proc/$pid/cgroup))) { print STDERR "$LOGPREF #$pid: unable to open cgroup ($!)\n" if($self->{debug}); return 0; } my $cg; { local $/; $cg = ; close(FCG); } # look for LXC cgroups return 0 unless($cg =~ /^\d+:[^:]+:\/lxc\/(.+)$/m); my $name = $1; unless($norestart) { print STDERR "$LOGPREF #$pid is part of LXC container '$name' and should be restarted\n" if($self->{debug}); $self->{lxc}->{$name}++; } else { print STDERR "$LOGPREF #$pid is part of LXC container '$name'\n" if($self->{debug}); } return 1; } sub get { my $self = shift; return map { ($_ => [qw(lxc-stop --reboot --name), $_]); } keys %{ $self->{lxc} }; } 1; needrestart-2.6/perl/lib/NeedRestart/CONT/docker.pm000066400000000000000000000045671266116133600222220ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::CONT::docker; use strict; use warnings; use parent qw(NeedRestart::CONT); use NeedRestart qw(:cont); use NeedRestart::Utils; my $LOGPREF = '[docker]'; needrestart_cont_register(__PACKAGE__) unless($<); sub new { my $class = shift; my $self = $class->SUPER::new(@_); die "Could not get NS PID of #1!\n" unless(defined($self->{nspid})); $self->{docker} = {}; return bless $self, $class; } sub check { my $self = shift; my $pid = shift; my $bin = shift; my $norestart = shift; my $ns = $self->get_nspid($pid); # stop here if no dedicated PID namespace is used return 0 if(!$ns || $ns == $self->{nspid}); unless(open(FCG, qq(/proc/$pid/cgroup))) { print STDERR "$LOGPREF #$pid: unable to open cgroup ($!)\n" if($self->{debug}); return 0; } my $cg; { local $/; $cg = ; close(FCG); } # look for docker cgroups return 0 unless($cg =~ /^\d+:[^:]+:\/system.slice\/docker-(.+)\.scope$/m); my $name = $1; $name =~ s/^([\da-f]{12})[\da-f]{52}$/$1/; unless($norestart) { print STDERR "$LOGPREF #$pid is part of docker container '$name' and should be restarted\n" if($self->{debug}); $self->{docker}->{$name}++; } else { print STDERR "$LOGPREF #$pid is part of docker container '$name'\n" if($self->{debug}); } return 1; } sub get { my $self = shift; return map { ($_ => [qw(docker restart), $_]); } keys %{ $self->{docker} }; } 1; needrestart-2.6/perl/lib/NeedRestart/Interp.pm000066400000000000000000000023141266116133600214350ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Interp; use strict; use warnings; sub new { my $class = shift; my $debug = shift; return bless { debug => $debug, }, $class; } sub isa($$) { my $self = shift; return 0; } sub source($$) { return (); } sub files($$) { return (); } 1; needrestart-2.6/perl/lib/NeedRestart/Interp/000077500000000000000000000000001266116133600210775ustar00rootroot00000000000000needrestart-2.6/perl/lib/NeedRestart/Interp/Java.pm000066400000000000000000000032121266116133600223140ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Interp::Java; use strict; use warnings; use parent qw(NeedRestart::Interp); use Getopt::Long; use NeedRestart qw(:interp); use NeedRestart::Utils; my $LOGPREF = '[Java]'; needrestart_interp_register(__PACKAGE__); sub isa { my $self = shift; my $pid = shift; my $bin = shift; return 1 if($bin =~ m@/.+/bin/java@); return 0; } sub source { # n/a (no shebang) return undef; } sub files { my $self = shift; my $pid = shift; my %ret = map { my $stat = nr_stat($_); $_ => ( defined($stat) ? $stat->{ctime} : undef ); } map { my $l = readlink; (defined($l) && $l =~ /\.(class|jar)( \(deleted\))?$/ ? $l : ()); } grep {1;} ; return %ret; } 1; needrestart-2.6/perl/lib/NeedRestart/Interp/Perl.pm000066400000000000000000000071531266116133600223450ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Interp::Perl; use strict; use warnings; use parent qw(NeedRestart::Interp); use Cwd qw(abs_path getcwd); use Getopt::Std; use NeedRestart qw(:interp); use NeedRestart::Utils; use Module::ScanDeps; my $LOGPREF = '[Perl]'; needrestart_interp_register(__PACKAGE__); sub isa { my $self = shift; my $pid = shift; my $bin = shift; return 1 if($bin =~ m@/usr/(local/)?bin/perl@); return 0; } sub source { my $self = shift; my $pid = shift; my $ptable = nr_ptable_pid($pid); my $cwd = getcwd(); chdir($ptable->{cwd}); # get original ARGV (my $bin, local @ARGV) = nr_parse_cmd($pid); # eat Perl's command line options my %opts; getopts('sTtuUWXhvV:cwdt:D:pnaF:l:0:I:m:M:fC:Sx:i:eE:', \%opts); # extract source file unless($#ARGV > -1) { chdir($cwd); print STDERR "$LOGPREF #$pid: could not get a source file, skipping\n" if($self->{debug}); return undef; } my $src = abs_path($ARGV[0]); chdir($cwd); unless(-r $src && -f $src) { print STDERR "$LOGPREF #$pid: source file not found, skipping\n" if($self->{debug}); print STDERR "$LOGPREF #$pid: reduced ARGV: ".join(' ', @ARGV)."\n" if($self->{debug}); return undef; } return $src; } sub files { my $self = shift; my $pid = shift; my $ptable = nr_ptable_pid($pid); unless($ptable->{cwd}) { print STDERR "$LOGPREF #$pid: could not get current working directory, skipping\n" if($self->{debug}); return (); } my $cwd = getcwd(); chdir($ptable->{cwd}); # get original ARGV (my $bin, local @ARGV) = nr_parse_cmd($pid); # eat Perl's command line options my %opts; getopts('sTtuUWXhvV:cwdt:D:pnaF:l:0:I:m:M:fC:Sx:i:eE:', \%opts); # extract source file unless($#ARGV > -1) { chdir($cwd); print STDERR "$LOGPREF #$pid: could not get a source file, skipping\n" if($self->{debug}); return (); } my $src = $ARGV[0]; unless(-r $src && -f $src) { chdir($cwd); print STDERR "$LOGPREF #$pid: source file not found, skipping\n" if($self->{debug}); print STDERR "$LOGPREF #$pid: reduced ARGV: ".join(' ', @ARGV)."\n" if($self->{debug}); return (); } # prepare include path environment variable my %e = nr_parse_env($pid); local %ENV; if(exists($e{PERL5LIB})) { $ENV{PERL5LIB} = $e{PERL5LIB}; } elsif(exists($ENV{PERL5LIB})) { delete($ENV{PERL5LIB}); } @Module::ScanDeps::IncludeLibs = (exists($opts{I}) ? ($opts{I}) : ()); my $href = scan_deps( files => [$src], recurse => 1, ); my %ret = map { my $stat = nr_stat($href->{$_}->{file}); $href->{$_}->{file} => ( defined($stat) ? $stat->{ctime} : undef ); } keys %$href; chdir($cwd); return %ret; } 1; needrestart-2.6/perl/lib/NeedRestart/Interp/Python.pm000066400000000000000000000112341266116133600227170ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Interp::Python; use strict; use warnings; use parent qw(NeedRestart::Interp); use Cwd qw(abs_path getcwd); use Getopt::Std; use NeedRestart qw(:interp); use NeedRestart::Utils; my $LOGPREF = '[Python]'; needrestart_interp_register(__PACKAGE__); sub isa { my $self = shift; my $pid = shift; my $bin = shift; return 1 if($bin =~ m@/usr/(local/)?bin/python@); return 0; } sub _scan($$$$$) { my $debug = shift; my $pid = shift; my $src = shift; my $files = shift; my $path = shift; my $fh; open($fh, '<', $src) || return; # find used modules my %modules = map { (/^\s*import\s+(\S+)/ ? ($1 => 1) : (/^\s*from\s+(\S+)\s+import\s+/ ? ($1 => 1) : ())) } <$fh>; close($fh); # track file $files->{$src}++; # scan module files if(scalar keys %modules) { foreach my $module (keys %modules) { $module =~ s@\.@/@g; $module .= '.py'; foreach my $p (@$path) { my $fn = ($p ne '' ? "$p/" : '').$module; &_scan($debug, $pid, $fn, $files, $path) if(!exists($files->{$fn}) && -r $fn && -f $fn); } } } } sub source { my $self = shift; my $pid = shift; my $ptable = nr_ptable_pid($pid); unless($ptable->{cwd}) { print STDERR "$LOGPREF #$pid: could not get current working directory, skipping\n" if($self->{debug}); return (); } my $cwd = getcwd(); chdir($ptable->{cwd}); # get original ARGV (my $bin, local @ARGV) = nr_parse_cmd($pid); # eat Python's command line options my %opts; getopts('BdEhim:ORQ:sStuvVW:x3?c:', \%opts); # extract source file unless($#ARGV > -1) { chdir($cwd); print STDERR "$LOGPREF #$pid: could not get a source file, skipping\n" if($self->{debug}); return undef; } my $src = abs_path($ARGV[0]); chdir($cwd); unless(-r $src && -f $src) { print STDERR "$LOGPREF #$pid: source file not found, skipping\n" if($self->{debug}); print STDERR "$LOGPREF #$pid: reduced ARGV: ".join(' ', @ARGV)."\n" if($self->{debug}); return undef; } return $src; } sub files { my $self = shift; my $pid = shift; my $ptable = nr_ptable_pid($pid); my $cwd = getcwd(); chdir($ptable->{cwd}); # get original ARGV (my $bin, local @ARGV) = nr_parse_cmd($pid); # eat Python's command line options my %opts; getopts('BdEhim:ORQ:sStuvVW:x3?c:', \%opts); # extract source file unless($#ARGV > -1) { chdir($cwd); print STDERR "$LOGPREF #$pid: could not get a source file, skipping\n" if($self->{debug}); return (); } my $src = $ARGV[0]; unless(-r $src && -f $src) { chdir($cwd); print STDERR "$LOGPREF #$pid: source file not found, skipping\n" if($self->{debug}); print STDERR "$LOGPREF #$pid: reduced ARGV: ".join(' ', @ARGV)."\n" if($self->{debug}); return (); } # prepare include path environment variable my %e = nr_parse_env($pid); local %ENV; if(exists($e{PYTHONPATH})) { $ENV{PYTHONPATH} = $e{PYTHONPATH}; } elsif(exists($ENV{PYTHONPATH})) { delete($ENV{PYTHONPATH}); } # get include path my ($pyread, $pywrite) = nr_fork_pipe2($self->{debug}, $ptable->{exec}, '-'); print $pywrite "import sys\nprint(sys.path)\n"; close($pywrite); my ($path) = <$pyread>; close($pyread); # look for module source files my @path; if(defined($path)) { chomp($path); $path =~ s/^\['//; $path =~ s/'\$//; @path = split("', '", $path); } else { print STDERR "$LOGPREF #$pid: failed to retrieve include path\n" if($self->{debug}); } my %files; _scan($self->{debug}, $pid, $src, \%files, \@path); my %ret = map { my $stat = nr_stat($_); $_ => ( defined($stat) ? $stat->{ctime} : undef ); } keys %files; chdir($cwd); return %ret; } 1; needrestart-2.6/perl/lib/NeedRestart/Interp/Ruby.pm000066400000000000000000000105001266116133600223520ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Interp::Ruby; use strict; use warnings; use parent qw(NeedRestart::Interp); use Cwd qw(abs_path getcwd); use Getopt::Std; use NeedRestart qw(:interp); use NeedRestart::Utils; my $LOGPREF = '[Ruby]'; needrestart_interp_register(__PACKAGE__); sub isa { my $self = shift; my $pid = shift; my $bin = shift; return 1 if($bin =~ m@/usr/(local/)?bin/ruby@); return 0; } sub _scan($$$$$) { my $debug = shift; my $pid = shift; my $src = shift; my $files = shift; my $path = shift; my $fh; open($fh, '<', $src) || return; # find used modules my %modules = map { (/^\s*load\s+['"]([^'"]+)['"]/ ? ($1 => 1) : (/^\s*require\s+['"]([^'"]+)['"]/ ? ("$1.rb" => 1) : ())) } <$fh>; close($fh); # track file $files->{$src}++; # scan module files if(scalar keys %modules) { foreach my $module (keys %modules) { foreach my $p (@$path) { my $fn = ($p ne '' ? "$p/" : '').$module; &_scan($debug, $pid, $fn, $files, $path) if(!exists($files->{$fn}) && -r $fn && -f $fn); } } } } sub source { my $self = shift; my $pid = shift; my $ptable = nr_ptable_pid($pid); unless($ptable->{cwd}) { print STDERR "$LOGPREF #$pid: could not get current working directory, skipping\n" if($self->{debug}); return (); } my $cwd = getcwd(); chdir($ptable->{cwd}); # get original ARGV (my $bin, local @ARGV) = nr_parse_cmd($pid); # eat Ruby's command line options my %opts; getopts('SUacdlnpswvy0:C:E:F:I:K:T:W:e:i:r:x:e:d:', \%opts); # extract source file unless($#ARGV > -1) { chdir($cwd); print STDERR "$LOGPREF #$pid: could not get a source file, skipping\n" if($self->{debug}); return undef; } my $src = abs_path($ARGV[0]); chdir($cwd); unless(-r $src && -f $src) { print STDERR "$LOGPREF #$pid: source file '$src' not found, skipping\n" if($self->{debug}); print STDERR "$LOGPREF #$pid: reduced ARGV: ".join(' ', @ARGV)."\n" if($self->{debug}); return undef; } return $src; } sub files { my $self = shift; my $pid = shift; my $ptable = nr_ptable_pid($pid); my $cwd = getcwd(); chdir($ptable->{cwd}); # get original ARGV (my $bin, local @ARGV) = nr_parse_cmd($pid); # eat Ruby's command line options my %opts; getopts('SUacdlnpswvy0:C:E:F:I:K:T:W:e:i:r:x:e:d:', \%opts); # extract source file unless($#ARGV > -1) { chdir($cwd); print STDERR "$LOGPREF #$pid: could not get a source file, skipping\n" if($self->{debug}); return (); } my $src = $ARGV[0]; unless(-r $src && -f $src) { chdir($cwd); print STDERR "$LOGPREF #$pid: source file '$src' not found, skipping\n" if($self->{debug}); print STDERR "$LOGPREF #$pid: reduced ARGV: ".join(' ', @ARGV)."\n" if($self->{debug}); return (); } # prepare include path environment variable my %e = nr_parse_env($pid); local %ENV; if(exists($e{RUBYLIB})) { $ENV{RUBYLIB} = $e{RUBYLIB}; } elsif(exists($ENV{RUBYLIB})) { delete($ENV{RUBYLIB}); } # get include path my $rbread = nr_fork_pipe($self->{debug}, $ptable->{exec}, '-e', 'puts $:'); my @path = <$rbread>; close($rbread); chomp(@path); my %files; _scan($self->{debug}, $pid, $src, \%files, \@path); my %ret = map { my $stat = nr_stat($_); $_ => ( defined($stat) ? $stat->{ctime} : undef ); } keys %files; chdir($cwd); return %ret; } 1; needrestart-2.6/perl/lib/NeedRestart/Kernel.pm000066400000000000000000000065321266116133600214220ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Kernel; use strict; use warnings; use NeedRestart::Utils; use Module::Find; use POSIX qw(uname); use constant { NRK_UNKNOWN => 0, NRK_NOUPGRADE => 1, NRK_ABIUPGRADE => 2, NRK_VERUPGRADE => 3, }; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( nr_kernel_check nr_kernel_vcmp NRK_UNKNOWN NRK_NOUPGRADE NRK_ABIUPGRADE NRK_VERUPGRADE ); my $LOGPREF = '[Kernel]'; sub nr_kernel_check($$) { my $debug = shift; my $ui = shift; my %vars; my ($sysname, $nodename, $release, $version, $machine) = uname; $vars{KVERSION} = $release; print STDERR "$LOGPREF $sysname: kernel release $release, kernel version $version\n" if($debug); # autoload Kernel modules foreach my $module (findsubmod NeedRestart::Kernel) { my @ret; unless(eval "use $module; \@ret = ${module}::nr_kernel_check_real(\$debug, \$ui);") { warn "Failed to load $module: $@" if($@ && $debug); } else { return @ret; } } return (NRK_UNKNOWN, %vars); } ## The following version number comparing stuff was taken from Dpkg::Version. ## The code has been adopted to be usable in needrestart w/o any additional ## dependencies. sub _nr_kversion_order { my ($x) = @_; if ($x eq '~') { return -1; } elsif ($x =~ /^\d$/) { return $x * 1 + 1; } elsif ($x =~ /^[A-Za-z]$/) { return ord($x); } else { return ord($x) + 256; } } sub _nr_kversion_strcmp($$) { my @a = map { _nr_kversion_order($_); } split(//, shift); my @b = map { _nr_kversion_order($_); } split(//, shift); while (1) { my ($a, $b) = (shift @a, shift @b); return 0 unless(defined($a) || defined($b)); $a ||= 0; # Default order for "no character" $b ||= 0; return 1 if($a > $b); return -1 if($a < $b); } } sub nr_kernel_vcmp($$) { # sort well known devel tags just as grub does my @v = map { my $v = $_; $v =~ s/[._-](pre|rc|test|git|old|trunk)/~$1/g; $v; } @_; my @a = split(/(?<=\d)(?=\D)|(?<=\D)(?=\d)/, shift(@v)); my @b = split(/(?<=\d)(?=\D)|(?<=\D)(?=\d)/, shift(@v)); while(1) { my ($a, $b) = (shift @a, shift @b); return 0 unless(defined($a) || defined($b)); $a ||= 0; $b ||= 0; if($a =~ /^\d+$/ && $b =~ /^\d+$/) { my $cmp = $a <=> $b; return $cmp if($cmp); } else { my $cmp = _nr_kversion_strcmp($a, $b); return $cmp if($cmp); } } } 1; needrestart-2.6/perl/lib/NeedRestart/Kernel/000077500000000000000000000000001266116133600210565ustar00rootroot00000000000000needrestart-2.6/perl/lib/NeedRestart/Kernel/Linux.pm000066400000000000000000000111371266116133600225160ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Kernel::Linux; use strict; use warnings; use NeedRestart::Utils; use NeedRestart::Kernel; use NeedRestart::Strings; use POSIX qw(uname); use Sort::Naturally; use Fcntl qw(SEEK_SET); use constant { NRK_LNX_GETVER_HELPER => q(/usr/lib/needrestart/vmlinuz-get-version), }; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( nr_linux_version_x86 nr_linux_version_generic ); my $LOGPREF = '[Kernel/Linux]'; sub nr_linux_version_x86($$) { my $debug = shift; my $fn = shift; my $fh; unless(open($fh, '<', $fn)) { print STDERR "$LOGPREF Could not open linux image ($fn): $!\n" if($debug); return undef; } binmode($fh); my $buf; # get kernel_version address from header seek($fh, 0x20e, SEEK_SET); read($fh, $buf, 2); my $offset = unpack 'v', $buf; # get kernel_version string seek($fh, 0x200 + $offset, SEEK_SET); read($fh, $buf, 128); close($fh); $buf =~ s/\000.*$//; return undef if($buf eq ''); unless($buf =~ /^\d+\.\d+/) { print STDERR "$LOGPREF Got garbage from linux image header ($fn): '$buf'\n" if($debug); return undef; } return ($buf, 1); } sub nr_linux_version_generic($$) { my $debug = shift; my $fn = shift; # use helper script to get version string if(-x NRK_LNX_GETVER_HELPER) { my $fh = nr_fork_pipe($debug, NRK_LNX_GETVER_HELPER, $fn, $debug); if($fh) { my $verstr = <$fh>; close($fh); if($verstr) { chomp($verstr); return ($verstr, 1) ; } } } else { print STDERR "$LOGPREF ".(NRK_LNX_GETVER_HELPER)." is n/a\n" if($debug); } # fallback trying filename $fn =~ s/[^-]*-//; if($fn =~ /^\d+\.\d+/) { print STDERR "$LOGPREF version from filename: $fn\n" if($debug); return ($fn, 0); } return undef; } sub nr_kernel_check_real($$) { my $debug = shift; my $ui = shift; my %vars; my ($sysname, $nodename, $release, $version, $machine) = uname; my $is_x86 = ($machine =~ /^(i\d86|x86_64)$/); $vars{KVERSION} = $release; die "$LOGPREF Not running on Linux!\n" unless($sysname eq 'Linux'); my @kfiles = reverse nsort ; $ui->progress_prep(scalar @kfiles, 'Scanning linux images...'); my %kernels; foreach my $fn (@kfiles) { $ui->progress_step; my $stat = nr_stat($fn); unless(defined($stat)) { print STDERR "$LOGPREF could not stat(2) on $fn\n" if($debug); next; } if($stat->{size} < 1000000) { print STDERR "$LOGPREF $fn seems to be too small\n" if($debug); next; } my $verstr; my $abidtc; if($is_x86) { ($verstr, $abidtc) = nr_linux_version_x86($debug, $fn); } unless(defined($verstr)) { ($verstr, $abidtc) = nr_linux_version_generic($debug, $fn); } unless(defined($verstr)) { print STDERR "$LOGPREF Could not get version string from $fn.\n" if($debug); next; } $vars{ABIDETECT} += $abidtc; my $iversion = $verstr; $iversion =~ s/^Linux version //; chomp($iversion); $iversion =~ s/\s.+$//; $kernels{$iversion} = (index($verstr, $release) != -1 && index($verstr, $version) != -1); print STDERR "$LOGPREF $fn => $verstr [$iversion]".($kernels{$iversion} ? '*' : '')."\n" if($debug); } $ui->progress_fin; unless(scalar keys %kernels) { print STDERR "$LOGPREF Did not find any linux images.\n" if($debug); return (NRK_UNKNOWN, %vars); } ($vars{EVERSION}) = reverse sort { nr_kernel_vcmp($a, $b); } keys %kernels; print STDERR "$LOGPREF Expected linux version: $vars{EVERSION}\n" if($debug); return (NRK_VERUPGRADE, %vars) if($vars{KVERSION} ne $vars{EVERSION}); return (NRK_ABIUPGRADE, %vars) unless(!$is_x86 || $kernels{$release}); return (NRK_NOUPGRADE, %vars); } 1; needrestart-2.6/perl/lib/NeedRestart/Kernel/kFreeBSD.pm000066400000000000000000000056161266116133600230110ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Kernel::kFreeBSD; use strict; use warnings; use NeedRestart::Utils; use NeedRestart::Kernel; use NeedRestart::Strings; use POSIX qw(uname); use Sort::Naturally; my $LOGPREF = '[Kernel/kFreeBSD]'; sub nr_kernel_check_real($$) { my $debug = shift; my $ui = shift; my %vars; my ($sysname, $nodename, $release, $version, $machine) = uname; $vars{KVERSION} = $release; die "$LOGPREF Not running on GNU/kFreeBSD!\n" unless($sysname eq 'GNU/kFreeBSD'); my @kfiles = reverse nsort ; $ui->progress_prep(scalar @kfiles, 'Scanning kfreebsd images...'); my %kernels; foreach my $fn (@kfiles) { $ui->progress_step; my $stat = nr_stat($fn); unless(defined($stat)) { print STDERR "$LOGPREF could not stat(2) on $fn\n" if($debug); next; } if($stat->{size} < 1000000) { print STDERR "$LOGPREF $fn seems to be too small\n" if($debug); next; } my $verstr = nr_strings_fh($debug, qr/FreeBSD \d.+:.+/, nr_fork_pipe($debug, qw(gunzip -c), $fn)); unless(defined($verstr)) { print STDERR "$LOGPREF Could not get version string from $fn.\n" if($debug); next; } my $iversion = $verstr; $iversion =~ s/^.*FreeBSD //; chomp($iversion); $iversion =~ s/\s.+$//; $verstr =~ s/(#\d+):/$1/; $kernels{$iversion} = (index($verstr, $release) != -1 && index($verstr, $version) != -1); print STDERR "$LOGPREF $fn => $verstr [$iversion]".($kernels{$iversion} ? '*' : '')."\n" if($debug); } $ui->progress_fin; unless(scalar keys %kernels) { print STDERR "$LOGPREF Did not find any kfreebsd images (/boot/kfreebsd-*)!\n" if($debug); return (NRK_UNKNOWN, %vars); } ($vars{EVERSION}) = reverse sort { nr_kernel_vcmp($a, $b); } keys %kernels; print STDERR "$LOGPREF Expected kfreebsd version: $vars{EVERSION}\n" if($debug); return (NRK_VERUPGRADE, %vars) if($vars{KVERSION} ne $vars{EVERSION}); return (NRK_ABIUPGRADE, %vars) unless($kernels{$release}); return (NRK_NOUPGRADE, %vars); } 1; needrestart-2.6/perl/lib/NeedRestart/Strings.pm000066400000000000000000000041471266116133600216330ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Strings; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( nr_strings nr_strings_fh ); my $LOGPREF = '[Strings]'; # This strings implementation has been taken from PPT 0.14: # # Copyright 1999 Nathan Scott Thompson # my $PUNCTUATION = join '\\', split //, q/`~!@#$%^&*()-+={}|[]\:";'<>?,.\//; #` my $PRINTABLE = '\w \t' . $PUNCTUATION; my $CHUNKSIZE = 4096; sub nr_strings_fh($$$) { my $debug = shift; my $re = shift; my $fh = shift; binmode($fh); my $offset = 0; while ($_ or read($fh, $_, $CHUNKSIZE)) { $offset += length($1) if(s/^([^$PRINTABLE]+)//o); my $string = ''; do { $string .= $1 if(s/^([$PRINTABLE]+)//o); } until ($_ or !read($fh, $_, $CHUNKSIZE)); if ($string =~ /$re/) { close($fh); return $string; } $offset += length($string); } close($fh); return undef; } sub nr_strings($$$) { my $debug = shift; my $re = shift; my $fn = shift; my $fh; unless(open($fh, '<', $fn)) { print STDERR "$LOGPREF Could not open file ($fn): $!\n" if($debug); return undef; } return nr_strings_fh($debug, $re, $fh); } 1; needrestart-2.6/perl/lib/NeedRestart/UI.pm000066400000000000000000000065241266116133600205200ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::UI; use strict; use warnings; use Term::ReadKey; sub new { my $class = shift; my $verbosity = shift; return bless { verbosity => $verbosity, progress => undef, }, $class; } sub progress_prep($$$) { my $self = shift; my ($max, $out) = @_; unless(($self->{verbosity} != 1) || !(-t *STDERR)) { # restore terminal if required (debconf) unless(-t *STDIN) { open($self->{fhin}, '<&', \*STDIN) || die "Can't dup stdin: $!\n"; open(STDIN, '< /dev/tty') || open(STDIN, '<&1'); } unless(-t *STDOUT) { open($self->{fhout}, '>&', \*STDOUT) || die "Can't dup stdout: $!\n"; open(STDOUT, '> /dev/tty') || open(STDOUT, '>&2'); } $self->{progress} = { count => 0, max => $max, }; } else { # disable progress indicator while being verbose $self->{progress} = undef; } $self->_progress_msg($out); } sub progress_step($) { my $self = shift; return unless defined($self->{progress}); $self->_progress_inc(); 1; } sub progress_fin($) { my $self = shift; return unless defined($self->{progress}); $self->_progress_fin(); # restore STDIN/STDOUT if required (debconf) open(STDIN, '<&', \*{$self->{fhin}}) || die "Can't dup stdin: $!\n" if($self->{fhin}); open(STDOUT, '>&', \*{$self->{fhout}}) || die "Can't dup stdout: $!\n" if($self->{fhout}); } sub _progress_msg { my $self = shift; return unless defined($self->{progress}); $self->{progress}->{msg} = shift; $self->_progress_out(); } sub _progress_inc { my $self = shift; $self->{progress}->{count}++; $self->_progress_out(); } sub _progress_out { my $self = shift; my ($columns) = GetTerminalSize(\*STDOUT); $columns -= 3; my $wmsg = int($columns * 0.7); $wmsg = length($self->{progress}->{msg}) if(length($self->{progress}->{msg}) < $wmsg); my $wbar = $columns - $wmsg - 1; printf("%-${wmsg}s [%-${wbar}s]\r", substr($self->{progress}->{msg}, 0, $wmsg), '=' x ($wbar*( $self->{progress}->{max} > 0 ? $self->{progress}->{count}/$self->{progress}->{max} : 0 ))); } sub _progress_fin { my $self = shift; $self->{progress}->{count} = 0; my ($columns) = GetTerminalSize(\*STDOUT); print $self->{progress}->{msg}, ' ' x ($columns - length($self->{progress}->{msg})), "\n"; } sub announce_abi { } sub announce_ver { } sub notice($$) { } sub query_pkgs($$$$$) { } sub query_conts($$$$$) { } 1; needrestart-2.6/perl/lib/NeedRestart/UI/000077500000000000000000000000001266116133600201535ustar00rootroot00000000000000needrestart-2.6/perl/lib/NeedRestart/UI/Debconf.pm000066400000000000000000000116401266116133600220530ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::UI::Debconf; use strict; use warnings; use parent qw(NeedRestart::UI); use NeedRestart qw(:ui); use Sort::Naturally; use constant { DCTMPL => '/usr/share/needrestart/needrestart.templates', }; BEGIN { die __PACKAGE__." is not supported as normal user!\n" if($<); } use Debconf::Client::ConfModule qw(:all); version('2.0'); capb('backup'); needrestart_ui_register(__PACKAGE__, NEEDRESTART_PRIO_HIGH); sub dcres(@) { return unless(scalar @_); my ($rc, @bulk) = @_; if($rc != 0 && $rc != 30) { stop; die "Debconf: $bulk[0]\n"; } return @bulk; } sub new { my $class = shift; my $verbosity = shift; dcres( x_loadtemplatefile(DCTMPL) ) if(-r DCTMPL); return bless { verbosity => $verbosity }, $class; } sub _announce { my $self = shift; my $templ = shift; my %vars = @_; foreach my $k (keys %vars) { dcres( subst($templ, $k, $vars{$k}) ); } dcres( fset($templ, 'seen', 0) ); dcres( settitle('needrestart/ui-kernel_title') ); dcres( input('critical', $templ) ); dcres( go ); } sub announce_abi { my $self = shift; $self->_announce('needrestart/ui-kernel_announce_abi', @_); } sub announce_ver { my $self = shift; $self->_announce('needrestart/ui-kernel_announce_ver', @_); } sub notice { my $self = shift; my $out = shift; print STDERR "$out\n" if($self->{verbosity}); } sub query_pkgs($$$$$$) { my $self = shift; my $out = shift; my $defno = shift; my $pkgs = shift; my $overrides = shift; my $cb = shift; # prepare checklist array my @l = nsort keys %$pkgs; # apply rc selection overrides my @selected = (); foreach my $pkg (@l) { my $found; foreach my $re (keys %$overrides) { next unless($pkg =~ /$re/); push(@selected, $pkg) if($overrides->{$re}); $found++; last; } push(@selected, $pkg) unless($defno || $found); } dcres(set('needrestart/ui-query_pkgs', join(', ', @selected))); dcres( subst('needrestart/ui-query_pkgs', 'OUT', $out) ); dcres( subst('needrestart/ui-query_pkgs', 'PKGS', join(', ', @l)) ); dcres( fset('needrestart/ui-query_pkgs', 'seen', 0) ); dcres( settitle('needrestart/ui-query_pkgs_title') ); dcres( input('critical', 'needrestart/ui-query_pkgs') ); my ($r) = dcres( go ); my ($s) = dcres( get('needrestart/ui-query_pkgs') ); stop; # Debconf kills STDOUT... try to restore it open(STDOUT, '> /dev/tty') || open(STDOUT, '>&2'); # user has canceled return unless(defined($s)); return if($r eq 'backup'); # get selected rc.d script my @s = split(/, /, $s); # restart each selected service script &$cb($_) for @s; } sub query_conts($$$$$$) { my $self = shift; my $out = shift; my $defno = shift; my $pkgs = shift; my $overrides = shift; my $cb = shift; # prepare checklist array my @l = nsort keys %$pkgs; # apply rc selection overrides my @selected = (); foreach my $pkg (@l) { my $found; foreach my $re (keys %$overrides) { next unless($pkg =~ /$re/); push(@selected, $pkg) if($overrides->{$re}); $found++; last; } push(@selected, $pkg) unless($defno || $found); } dcres(set('needrestart/ui-query_conts', join(', ', @selected))); dcres( subst('needrestart/ui-query_conts', 'OUT', $out) ); dcres( subst('needrestart/ui-query_conts', 'CONTS', join(', ', @l)) ); dcres( fset('needrestart/ui-query_conts', 'seen', 0) ); dcres( settitle('needrestart/ui-query_conts_title') ); dcres( input('critical', 'needrestart/ui-query_conts') ); my ($r) = dcres( go ); my ($s) = dcres( get('needrestart/ui-query_conts') ); stop; # Debconf kills STDOUT... try to restore it open(STDOUT, '> /dev/tty') || open(STDOUT, '>&2'); # user has canceled return unless(defined($s)); return if($r eq 'backup'); # get selected rc.d script my @s = split(/, /, $s); # restart each selected service script &$cb($_) for @s; } 1; needrestart-2.6/perl/lib/NeedRestart/UI/stdio.pm000066400000000000000000000064241266116133600216410ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::UI::stdio; use strict; use warnings; use parent qw(NeedRestart::UI); use NeedRestart qw(:ui); needrestart_ui_register(__PACKAGE__, NEEDRESTART_PRIO_LOW); sub _announce { my $self = shift; my $message = shift; my %vars = @_; print "Pending kernel upgrade!\n\nRunning kernel version:\n $vars{KVERSION}\n\nDiagnostics:\n $message\n\nRestarting the system to load the new kernel will not be handled automatically, so you should consider rebooting. [Return]\n"; ; } sub announce_abi { my $self = shift; my %vars = @_; $self->_announce('The currently running kernel has an ABI compatible upgrade pending.', %vars); } sub announce_ver { my $self = shift; my %vars = @_; $self->_announce("The currently running kernel version is not the expected kernel version $vars{EVERSION}.", %vars); } sub notice($$) { my $self = shift; my $out = shift; print "$out\n"; } sub _query($$) { my $self = shift; my($query, $def) = @_; my @def = ($def eq 'Y' ? qw(yes no auto stop) : qw(no yes auto stop)); my $i; do { print "$query [", ($def eq 'Y' ? 'Ynas?' : 'yNas?'), '] '; if($self->{stdio_same}) { my $s = $self->{stdio_same}; $s = ($def eq 'Y' ? 'yes' : 'no') if($s eq 'auto'); print "$s\n"; return $s; } $i = ; unless(defined($i)) { $i = 'n'; last; } $i = lc($i); chomp($i); $i =~ s/^\s+//; $i =~ s/\s+$//; if($i eq '?') { print <{stdio_same} = 'auto') if($i eq 'auto'); return ($self->{stdio_same} = 'no') if($i eq 'stop'); return $i; } sub query_pkgs($$$$$$) { my $self = shift; my $out = shift; my $def = shift; my $pkgs = shift; my $overrides = shift; my $cb = shift; delete($self->{stdio_same}); print "$out\n"; foreach my $rc (sort keys %$pkgs) { my ($or) = grep { $rc =~ /$_/; } keys %$overrides; my $d = (defined($or) ? ($overrides->{$or} ? 'Y' : 'N') : ($def ? 'N' : 'Y')); &$cb($rc) if($self->_query("Restart $rc?", $d) eq 'yes'); } } sub query_conts($$$$$$) { my $self = shift; $self->query_pkgs(@_); } 1; needrestart-2.6/perl/lib/NeedRestart/Utils.pm000066400000000000000000000066741266116133600213110ustar00rootroot00000000000000# needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2015 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # package NeedRestart::Utils; use strict; use warnings; use Proc::ProcessTable; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( nr_ptable nr_ptable_pid nr_parse_cmd nr_parse_env nr_readlink nr_stat nr_fork_pipe nr_fork_pipew nr_fork_pipe2 ); my %ptable = map {$_->pid => $_} @{ new Proc::ProcessTable(enable_ttys => 1)->table }; sub nr_ptable() { return \%ptable; } sub nr_ptable_pid($) { my $pid = shift; return $ptable{$pid}; } sub nr_parse_cmd($) { my $pid = shift; my $fh; open($fh, '<', "/proc/$pid/cmdline") || return (); local $/ = "\000"; my @cmdline = <$fh>; chomp(@cmdline); close($fh); return @cmdline; } sub nr_parse_env($) { my $pid = shift; my $fh; open($fh, '<', "/proc/$pid/environ") || return (); local $/ = "\000"; my @env = <$fh>; chomp(@env); close($fh); return map { (/^([^=]+)=(.*)$/ ? ($1, $2) : ()) } @env; } my %readlink; sub nr_readlink($) { my $pid = shift; return $readlink{$pid} if(exists($readlink{$pid})); my $fn = "/proc/$pid/exe"; return ($readlink{$pid} = readlink($fn)); } my %stat; sub nr_stat($) { my $fn = shift; return $stat{$fn} if(exists($stat{$fn})); my @stat = stat($fn); return undef unless($#stat > -1); $stat{$fn} = { dev => $stat[0], ino => $stat[1], mode => $stat[2], nlink => $stat[3], uid => $stat[4], gid => $stat[5], rdev => $stat[6], size => $stat[7], atime => $stat[8], mtime => $stat[9], ctime => $stat[10], blksize => $stat[11], blocks => $stat[12], }; return $stat{$fn}; } sub nr_fork_pipe($@) { my $debug = shift; my $pid = open(HPIPE, '-|'); defined($pid) || die "Can't fork: $!\n"; if($pid == 0) { close(STDIN); close(STDERR) unless($debug); undef $ENV{LANG}; exec(@_); exit; } \*HPIPE } sub nr_fork_pipew($@) { my $debug = shift; my $pid = open(HPIPE, '|-'); defined($pid) || die "Can't fork: $!\n"; if($pid == 0) { close(STDOUT); close(STDERR) unless($debug); undef $ENV{LANG}; exec(@_); exit; } \*HPIPE } sub nr_fork_pipe2($@) { my $debug = shift; my ($pread, $fhwrite); pipe($pread, $fhwrite) || die "Can't pipe: $!\n"; my $fhread; my $pid = open($fhread, '-|'); defined($pid) || die "Can't fork: $!\n"; if($pid == 0) { open(STDIN, '<&', $pread) || die "Can't dup stdin: $!\n"; close(STDERR) unless($debug); undef $ENV{LANG}; exec(@_); exit; } close($pread); return ($fhread, $fhwrite); } 1;