IPC-System-Simple-1.30/0000755000175000017500000000000013636261621014377 5ustar jkeenanjkeenanIPC-System-Simple-1.30/META.yml0000644000175000017500000000170013636261621015646 0ustar jkeenanjkeenan--- abstract: 'Run commands simply, with detailed diagnostics' author: - 'Paul Fenwick ' build_requires: ExtUtils::MakeMaker: '0' File::Basename: '0' Test: '0' Test::More: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: IPC-System-Simple no_index: directory: - t - inc requires: Carp: '0' Exporter: '0' List::Util: '0' POSIX: '0' Scalar::Util: '0' constant: '0' perl: '5.006' re: '0' strict: '0' warnings: '0' resources: bugtracker: https://github.com/pjf/ipc-system-simple/issues homepage: http://thenceforward.net/perl/modules/IPC-System-Simple/ repository: https://github.com/pjf/ipc-system-simple.git version: '1.30' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' IPC-System-Simple-1.30/MANIFEST.SKIP0000644000175000017500000000065713635471634016313 0ustar jkeenanjkeenan^blib/ ^Makefile$ ^Makefile\.[a-z]+$ ^pm_to_blib$ CVS/.* ,v$ ^tmp/ \.old$ \.bak$ \.tmp$ \.swp$ ~$ ^# \.shar$ \.tar$ \.tgz$ \.tar\.gz$ \.zip$ \.DS_Store$ _uu$ \.svn cover_db/ coverage/ html/ learn/ research/ superseded/ svndiff/ ^.cvsignore ^init ^results ^htmlify \.git/ MYMETA.*$ .version_info.pl \.gitignore \.travis.yml ^README.md ^.README.pod \.appveyor.yml \.perlcriticrc t/dir with spaces/hello.c t/dir with spaces/hello.exe IPC-System-Simple-1.30/Changes0000644000175000017500000002727313636261102015677 0ustar jkeenanjkeenanRevision history for Perl extension IPC::System::Simple. 1.30 2020-03-23 21:16 America/New York * SUBSTANCE: On MSWin32, make Win32::Process a prerequisite (needed for non-Strawberry Perl builds). As recommended by A Sinan Unur. 1.29 2020-03-22 08:22 America/New York * SUBSTANCE: Better workaround for bug in perl-5.8.9 (GHI 23); contributed by Slaven Rezić. 1.28 2020-03-21 21:39 America/New York * SUBSTANCE: Improved handling of shell commands on Windows, mostly per suggestions by David Wheeler. This should get us closer to resolving Win32-related issues. (There should be no change of functionality on Unix-like platforms.) * TESTING: Add t/args.t per David Wheeler. Modify t/win32.t per @dylanstreb. * META: Added Travis and AppVeyor configuration files. Eliminated use of Dist::Zilla for build. Using older, but more reliable and better understood (by maintainer) ExtUtils::MakeMaker-based configuration. Add LICENSE, README, Makefile.PL, MANIFEST and MANIFEST.SKIP; remove dist.ini. Move author testing to xt/directory. 1.28_001 2020-03-21 16:42 America/NewYork TRIAL RELEASE only Attempting to resolve numerous Win32 issues 1.26 2020-01-24 20:47 America/NewYork * BUILD: Update FAIL_POSIX warning message Per: https://github.com/pjf/ipc-system-simple/pull/28. Thanks to scop. * TEST: t/07_taint.t: Use executable name as source of taintedness Addresses https://github.com/pjf/ipc-system-simple/issues/21 Thanks to Petr Písař. * OTHER: Typographic corrections: rt.cpan.org 60211; leonerd++ rt.cpan.org 86403; dsteinbrunner++ Add Travis configuration. 1.26-TRIAL 2020-01-24 03:43:20 GMT TRIAL release only 1.25 2013-10-20 13:38:32 Pacific/Auckland * BUILD: No longer ship unrequired file Debian_CPANTS.txt. (GH #7, thanks to real-dam) 1.24 2013-10-18 16:27:39 Australia/Melbourne * BUILD: No longer mark BSD::Resource as required (GH #6). * TEST: Skip core-dump tests on OS X. They're not as straightforward as the test script would like. (GH #5). 1.23 2013-10-08 14:50:50 Australia/Melbourne * BUGFIX: Silence "Statement unlikely to be reached" warning (Karen Etheridge) * BUGFIX: Repository information fix, and typo fixes (@dsteinbrunner) * BUILD: Converted to using dzil. 1.22 Tue Oct 8 14:49:43 AUSEST 2013 * Same as 1.23 release, but with booched changelog. Oops! :) 1.21 Tue Mar 23 12:08:47 AUSEST 2010 * TEST: t/win32.t has more sane handling of skipped and unimplimented tests. * TEST: Author tests no longer leave the permissions of not_an_exe.txt permanently changed. * BUGFIX: capture/capturex no longer break STDOUT when running an unknown command under Windows. Many thanks to Jan Krynicky for a fix. (RT #48319) * BUILD: Upgraded to Module::Install 0.93. 1.20 Sat Jan 9 15:08:41 AUSEST 2010 * TEST: t/win32.t no longer claims to have more tests than it really has. This fixes an install issue under Windows. RT #53124. Thanks to Erez Schatz and Curtis Jewell for spotting this. 1.19 Fri Dec 4 14:14:25 AUSEST 2009 * TEST: Added tests to ensure correct behaviour when calling commands in Windows which are contained in directories that contain spaces. (These tests are currently skiped, as they're testing for a known bug.) * BUGFIX: Spurious warnings about redefining POSIX macros no longer plague Windows systems. 1.18 Sun Feb 8 19:09:15 AUSEDT 2009 * BUGFIX: IPC::System::Simple should now compile cleanly under 5.6.0 and 5.6.1 (as well as 5.6.2+). Many thanks to David Golden for spotting this bug. (RT #43098) * DOCUMENTATION: "Advanced" is now spelt correctly under in the section "Advanced Usage". Many thanks to Raymond Wan for spotting this typo. (RT #42705) 1.17 Fri Dec 19 00:45:16 AUSEDT 2008 * TEST: Tests to ensure that passing undefined values to systemx() do not produce malformed errors, but instead well-formed errors. Many thanks to Nadim Khemir for spotting this. RT #41149. * BUGFIX: Workaround for a bug under Perl 5.10 where on some platforms coredumps were not being reported in $?. Many thanks to the Debian Perl folks for finding this, particularly Gregor Herrmann. * TEST: Better diagnostics from t/08_core.t. * TEST: t/08_core.t now cleans up its core files after running. Thanks to Gregor Herrmann for spotting this. * TEST: t/08_core.t is now a main test, rather than an author-only test. * BUGFIX: Attempting to call an undefined command is now a fatal error. * VERSION: Since ISS is now very stable, and provides a significantly improved interface to the default system() command, the major version number has been incremented. There are no incompatible changes with previous version. The increment of the major version number is to indicate stability only. 0.16 Sun Sep 14 11:29:17 AUSEST 2008 * DOCUMENTATION: Updated documentation on $EXITVAL to provide extra clarification. Many thanks again to Elliot Shank for the feedback! * DOCUMENTATION: Noted that run() and system() are aliases for each other. Thanks again for Elliot Shank for the feedback. * DOCUMENTATION: Fixed a few missing double-quotes in the systemx() documentation. Thanks to Andrew Dent for spotting these! * DOCUMENTATION: Added a feedback section. If you find this module useful, consider rating it at http://cpanratings.perl.org/rate/?distribution=IPC-System-Simple * BUILD: Upgraded to Module::Install 0.77 0.15 Sat Jul 19 23:26:18 PDT 2008 - runx() is now correctly in @EXPORT_OK. Many thanks to Elliot "clonezone" Shank for spotting this in RT #37793. - Added exports test case. 0.14 Sat Jul 19 00:26:01 AEST 2008 - We should now recognise "not implemented on this architecture" POSIX errors from Perl 5.11.0 - Fixed an invalid specification of resources in META.yml. 0.13 Thu Jul 17 20:36:42 AEST 2008 - Added examples directory with examples. - Updated manifest to include error message regession tests. - Test::Kwalitee is now marked as an author-only test. - Added tests for correct handling of 32-bit values in win32.t. Corrected documentation regarding Win32 exitval size. Thanks to Jan Dubois for alerting me to the 32-bitness of Windows exit values. - Added tests to ensure that newlines are properly stripped with single-arg system and capture. - Pod and Pod Coverage tests are now marked as author-only. - Added perl core identical rules for determining the Windows shell. - Added META.yml resources, including blog, bugtracker, forum, and repository. - Additional tests to ensure returns from capture() are properly tainted (when running in taint mode). - Added systemx() and capturex() that _never_ invoke the shell. Thanks to ikegami for prodding me on these. (RT #37683) 0.12 Fri Jun 6 17:15:52 AEST 2008 - Corrected doubled package names in some diagnostics when used in taint mode, or when run() is called without arguments. 0.11 Fri Jun 6 12:15:39 AEST 2008 - Drop-in system() replacement available. - Simplified synopsis statement. - Provided advanced usage documentation. - Added comparison to other system APIs. - Updated Changes to put most recent changes at top. - Makefile.PL tweaks to build cleanly under Debian's dh-make-perl. - Upgraded to Module::Install 0.75 with custom bugfixes. 0.10 Thu May 15 00:39:59 AEST 2008 - Multi-arg captures now work on Perl 5.6.x. (RT #35866) - Minor corrections to diagnostics documentation. - Adjusted module summary. 0.09 Mon May 12 23:38:29 AEST 2008 - Test suite now provides better diagnostics if taint tests fail unexpectedly early. - Multi-argument run() will now search $ENV{PATH} under Win32. - Documented $ENV{PATH} foibles on Win32 systems under the Windows-specific notes section of the documentation. - Implemented capture(), which is the equivalent of run() for backticks. - General documentation improvements and clarifications, thanks to Jacinta Richardson. - The special value EXIT_ANY (aka [-1]) can be used to indicate that any exit value is acceptable from a process. - Added author-only Perl::Critic tests. - Updated diagnostics section in POD. - License changed to that of Perl 5.6.0, or any later version. - LICENSE file added to distribution. - Moved to Module::Install for build system. - Better failures when seeing unexpected things from POSIX.pm - Support for detecting core-dumps added. - All failure messages now use double-quotes when quoting variable sections. - Diagnostics documentation rearraged to have most common errors listed first. 0.08 Sun Apr 13 13:38:49 AEST 2008 - Numerous documentation fixes thanks to Matt Kraai (RT #34896) - Updated t/07_taint.t to not fail on systems that have zero-length environment strings. - Updated taint checks to always run on 5.6.x, under 0.07 they would never run on older perls. 0.07 Sat Apr 12 11:57:28 AEST 2008 - Changed tests to use SIGKILL rather than SIGINT to avoid complications on systems where SIGINT is masked. - All dependencies now explicitly stated in Makefile.PL. - run() now explicitly checked for tainted arguments and environment, and provides helpful diagnostics if found. - Removed mention of unimplemented capture() command in documentation. 0.06 Thu Sep 6 18:09:50 AEST 2007 - Warnings are no longer emitted on failed calls to system(). - Multiple argument run() no longer uses the shell under Win32. - 16-bit native exit values are now returned on Win32 systems. - WIF* POSIX commands that are not defined are more correctly handled, particularly under Perl 5.6. Thanks to Laurent Laporte for the bug report (RT #29080). - README and POD improved. 0.05 Mon Apr 9 16:22:22 AEST 2007 - Removed spurious double-quotes in error messages reporting unexpected exit values and an internal error message. Thanks to Jon Swartz for spotting these. 0.04 Mon Oct 30 15:14:53 AEST 2006 - Fixed path issue with tests that would cause them to fail on some systems where "." was not in the $ENV{PATH} - Tests now always use the system-configured perl for invoking commands. 0.03 Tue Jul 25 12:07:09 AEST 2006 - Documentation improvements 0.02 Tue Jul 25 12:05:50 AEST 2006 - Updated to emulate WIFEXITED on systems that don't provide them - Signal tests skipped under Win32 - Better testing 0.01 Fri Jul 21 19:27:45 2006 - original version; created by h2xs 1.23 with options -b 5.6.0 -X IPC::System::Simple IPC-System-Simple-1.30/META.json0000644000175000017500000000332113636261621016017 0ustar jkeenanjkeenan{ "abstract" : "Run commands simply, with detailed diagnostics", "author" : [ "Paul Fenwick " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "IPC-System-Simple", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Exporter" : "0", "List::Util" : "0", "POSIX" : "0", "Scalar::Util" : "0", "constant" : "0", "perl" : "5.006", "re" : "0", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "File::Basename" : "0", "Test" : "0", "Test::More" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/pjf/ipc-system-simple/issues" }, "homepage" : "http://thenceforward.net/perl/modules/IPC-System-Simple/", "repository" : { "type" : "git", "url" : "https://github.com/pjf/ipc-system-simple.git", "web" : "https://github.com/pjf/ipc-system-simple" } }, "version" : "1.30", "x_serialization_backend" : "JSON::PP version 4.02" } IPC-System-Simple-1.30/LICENSE0000644000175000017500000004365513635471634015427 0ustar jkeenanjkeenanThis software is copyright (c) 2020 by Paul Fenwick. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2020 by Paul Fenwick. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our 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. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, 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 a 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 tell them 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. 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 Agreement 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 work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 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 General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual 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 General Public License. d) 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. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 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 Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying 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. 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. 7. 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 the 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 the license, you may choose any version ever published by the Free Software Foundation. 8. 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 9. 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. 10. 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 Appendix: 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 humanity, 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) 19yy 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 1, 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) 19xx 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 a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2020 by Paul Fenwick. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End IPC-System-Simple-1.30/MANIFEST0000644000175000017500000000122513636261621015530 0ustar jkeenanjkeenanChanges examples/rsync-backup.pl lib/IPC/System/Simple.pm LICENSE Makefile.PL MANIFEST This list of files MANIFEST.SKIP README t/01_load.t t/02_exit.t t/03_signal.t t/04_capture.t t/05_multi_capture.t t/06_fail.t t/07_taint.t t/08_core.t t/09_system.t t/10_formatting.t t/11_newlines.t t/12_systemx.t t/13_exports.t t/14_uninitialised.t t/args.t t/exiter.pl t/internal.t t/not_an_exe.txt t/output.pl t/signaler.pl t/win32.t xt/author-critic.t xt/author-pod-coverage.t xt/author-pod-syntax.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) IPC-System-Simple-1.30/xt/0000755000175000017500000000000013636261620015031 5ustar jkeenanjkeenanIPC-System-Simple-1.30/xt/author-pod-coverage.t0000644000175000017500000000053613635471634021104 0ustar jkeenanjkeenan#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests. use Test::Pod::Coverage 1.08; use Pod::Coverage::TrustPod; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); IPC-System-Simple-1.30/xt/author-pod-syntax.t0000644000175000017500000000045413635471634020636 0ustar jkeenanjkeenan#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); IPC-System-Simple-1.30/xt/author-critic.t0000644000175000017500000000040313635471634017777 0ustar jkeenanjkeenan#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use strict; use warnings; use Test::Perl::Critic (-profile => "perlcritic.rc") x!! -e "perlcritic.rc"; all_critic_ok(); IPC-System-Simple-1.30/Makefile.PL0000644000175000017500000000451713636260614016361 0ustar jkeenanjkeenan# This file was originally generated by Dist::Zilla::Plugin::MakeMaker v6.012, # but is now manually maintained. use strict; use warnings; use 5.006; use ExtUtils::MakeMaker; my $mm_ver = ExtUtils::MakeMaker->VERSION; my %WriteMakefileArgs = ( "ABSTRACT" => "Run commands simply, with detailed diagnostics", "AUTHOR" => "Paul Fenwick ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "IPC-System-Simple", "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.006", "NAME" => "IPC::System::Simple", "PREREQ_PM" => { "Carp" => 0, "Exporter" => 0, "List::Util" => 0, "POSIX" => 0, "Scalar::Util" => 0, "constant" => 0, "re" => 0, "strict" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "File::Basename" => 0, "Test" => 0, "Test::More" => 0 }, "VERSION_FROM" => 'lib/IPC/System/Simple.pm', "test" => { "TESTS" => "t/*.t" }, ($mm_ver < 6.46 ? () : (META_MERGE => { 'meta-spec' => { version => 2 }, dynamic_config => 1, resources => { homepage => 'http://thenceforward.net/perl/modules/IPC-System-Simple/', repository => { url => 'https://github.com/pjf/ipc-system-simple.git', web => 'https://github.com/pjf/ipc-system-simple', type => 'git', }, bugtracker => { web => 'https://github.com/pjf/ipc-system-simple/issues', }, }, })), ); my %FallbackPrereqs = ( "Carp" => 0, "Exporter" => 0, "File::Basename" => 0, "List::Util" => 0, "POSIX" => 0, "Scalar::Util" => 0, "Test" => 0, "Test::More" => 0, "constant" => 0, "re" => 0, "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; my %win32_modules = ( 'Win32::ShellQuote' => 0, 'Win32::Process' => 0, ); if ( $^O eq 'MSWin32' ) { for my $k (keys %win32_modules) { $WriteMakefileArgs{PREREQ_PM}{$k} = $win32_modules{$k}; $FallbackPrereqs{$k} = $win32_modules{$k}; } } WriteMakefile(%WriteMakefileArgs); IPC-System-Simple-1.30/README0000644000175000017500000000060013635471634015261 0ustar jkeenanjkeenanThis archive contains the distribution IPC-System-Simple, version 1.27: Run commands simply, with detailed diagnostics This software is copyright (c) 2020 by Paul Fenwick. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v6.012. IPC-System-Simple-1.30/examples/0000755000175000017500000000000013636261620016214 5ustar jkeenanjkeenanIPC-System-Simple-1.30/examples/rsync-backup.pl0000755000175000017500000000275113612375531021163 0ustar jkeenanjkeenan#!/usr/bin/perl -w # The following example code uses IPC::System::Simple to mount # a /mnt/backup directory, run an rsync command, and then unmount # the directory again. use strict; use IPC::System::Simple qw(run capture); use POSIX qw(nice strftime); use Fatal qw(open close nice); use constant NICE_VALUE => 10; die "Must be root" if $> != 0; nice(NICE_VALUE); my $mounted = 0; my $today = strftime('%Y-%m-%d',localtime); # The capture() from IPC::System::Simple either works, or dies. my $machine_name = capture("hostname"); open(my $mtab_fh, '<', '/etc/mtab'); while (<$mtab_fh>) { if (m{/mnt/backup}) { $mounted = 1; last; } } close($mtab_fh); if (not $mounted) { # Our run() from IPC::System::Simple either works, or dies. run(qw(/bin/mount /mnt/backup)); } my $last_backup = ''; foreach my $dir ( glob("/mnt/backup/$machine_name/*") ) { next if not -d $dir; # 'gt' is correct here, since we're delaing with YYYY-MM-DD if ($dir gt $last_backup) { $last_backup = $dir; } } die "Cannot find last backup" unless $last_backup; # 0 - Successful backup # 24 - Files disappeared during backup. This is expected on # an active filesystem, and not considered an error. run([0,24], qw(/usr/bin/rsync -aH --exclude-from=/etc/rsync-ignore), "--link-dest=$last_backup","/", "/mnt/backup/teddybear/$today", ); # Unmount our filesystem if we found it unmounted to begin with. # Again, run() either succeeds, or dies. if (not $mounted) { run(qw(/bin/umount /mnt/backup)); } IPC-System-Simple-1.30/t/0000755000175000017500000000000013636261620014641 5ustar jkeenanjkeenanIPC-System-Simple-1.30/t/args.t0000644000175000017500000000572213635471634015777 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 56; use IPC::System::Simple qw(run runx system systemx capture capturex); use Config; use File::Basename qw(fileparse); my $perl = $Config{perlpath}; $perl .= $Config{_exe} if $^O ne 'VMS' && $perl !~ m/$Config{_exe}$/i; my $tmp = 'test.tmp'; my $script = qq{ open my \$fh, '>', '$tmp' or die "Cannot write to $tmp: \$!\\n"; print {\$fh} "\$_\\n" for \@ARGV; }; chdir 't'; END { unlink $tmp; } my $slurp = sub { open my $fh, '<', $tmp or die "Cannot read $tmp: $!\n"; return join '', <$fh>; }; for my $spec ( ['single arg', 'foo'], ['multiple args', 'x', 'y', 'z'], ['arg with spaces', 'foo', 'bar baz'], ) { my ($desc, @args) = @{ $spec }; my $exp = join "\n", @args, ''; # Test run. my $exit = eval { run $perl, '-e', $script, @args }; is $@, "", "Should have no error from runx with $desc"; is $exit, 0, "Should have exit 0 from runx with $desc"; is $slurp->(), $exp, "Should have passed $desc from run"; # Test system. $exit = eval { system $perl, '-e', $script, @args }; is $@, "", "Should have no error from systemx with $desc"; is $exit, 0, "Should have exit 0 from systemx with $desc"; is $slurp->(), $exp, "Should have passed $desc from system"; # Test runx. $exit = eval { runx $perl, '-e', $script, @args }; is $@, "", "Should have no error from runx with $desc"; is $exit, 0, "Should have exit 0 from runx with $desc"; is $slurp->(), $exp, "Should have passed $desc from runx"; # Test systemx. $exit = eval { systemx $perl, '-e', $script, @args }; is $@, "", "Should have no error from systemx with $desc"; is $exit, 0, "Should have exit 0 from systemx with $desc"; is $slurp->(), $exp, "Should have passed $desc from systemx"; # Test capture. my $output = eval { capture $perl, '-e', 'print "$_\n" for @ARGV', @args }; is $@, "", "Should have no error from capture with $desc"; is $output, $exp, "Should have passed $desc from capture"; # Test capturex. $output = eval { capturex $perl, '-e', 'print "$_\n" for @ARGV', @args }; is $@, "", "Should have no error from capturex with $desc"; is $output, $exp, "Should have passed $desc from capturex"; } # Make sure redirection works, too. my $exit = eval { run "$perl output.pl > $tmp" }; is $@, "", "Should have no error from run with redirection"; is $exit, 0, "Should have exit 0 from run with redirection"; is $slurp->(), "Hello\nGoodbye\n", "Should have redirected text run"; $exit = eval { system "$perl output.pl > $tmp" }; is $@, "", "Should have no error from systemx with redirection"; is $exit, 0, "Should have exit 0 from systemx with redirection"; is $slurp->(), "Hello\nGoodbye\n", "Should have redirected text systemx"; # And single-string capture. my $output = eval { capture "$perl output.pl" }; is $@, "", "Should have no error from single-string capture"; is $output, "Hello\nGoodbye\n", "Should have output from capture"; IPC-System-Simple-1.30/t/12_systemx.t0000644000175000017500000000204713614670265017054 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use IPC::System::Simple qw(system systemx capture capturex); use Config; use Test::More tests => 7; my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } chdir("t"); # Ignore return, since we may already be in t/ my $exit_test = "$perl_path exiter.pl 0"; eval { system($exit_test); }; is($@,"","system invokes the shell"); eval { systemx($exit_test); }; ok($@,"systemx does not invoke the shell"); eval { systemx($perl_path, "exiter.pl", 0); }; is($@,"", "multi-arg systemx works"); my $output_test = "$perl_path output.pl"; my $output; eval { $output = capture($output_test); }; like($output, qr/Hello/, "capture invokes the shell"); undef $output; eval { $output = capturex($output_test); }; ok($@, "capturex does not invoke the shell"); eval { $output = capturex($perl_path, "output.pl"); }; is($@,"","multi-arg capturex works"); like($output, qr/Hello/, "multi-arg capturex captures"); IPC-System-Simple-1.30/t/03_signal.t0000644000175000017500000000110313612375531016601 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More; use Config; use constant SIGKILL => 9; if ($^O eq "MSWin32") { plan skip_all => "Signals not implemented on Win32"; } else { plan tests => 3; } # We want to invoke our sub-commands using Perl. my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } use_ok("IPC::System::Simple","run"); chdir("t"); run([1],$perl_path,"signaler.pl",0); ok(1); eval { run([1],$perl_path,"signaler.pl",SIGKILL); }; like($@, qr/died to signal/); IPC-System-Simple-1.30/t/06_fail.t0000755000175000017500000000227313612721641016253 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 8; use Config; use_ok('IPC::System::Simple', qw(run capture)); # Run a command that doesn't exist. The exit values # 1 and 127 are special, as they indicate command-not-found # from the Windows and Unix shells respectively. # Bad command, run eval { run([1,127],"xyzzy42this_command_does_not_exist","foo"); }; like ($@, qr{failed to start}, "Non-existent, run "); # Bad calls to I::S::Simple eval { run(); }; like($@, qr{IPC::System::Simple::run called with no arguments},"Empty call to run"); eval { capture(); }; like($@, qr{IPC::System::Simple::capture called with no arguments},"Empty call to capture"); eval { run([0..5]); }; like($@, qr{IPC::System::Simple::run called with no command},"No command passed to run"); eval { capture([0..5]); }; like($@, qr{IPC::System::Simple::capture called with no command},"No command passed to capture"); # Bad command, capture eval { capture([1,127],"xyzzy42this_command_does_not_exist"); }; like ($@, qr{failed to start}, "Not existent, capture"); # Bad command, capture w/args eval { capture([1,127],"xyzzy42this_command_does_not_exist",1); }; like ($@, qr{failed to start}, "Not existent, capture"); IPC-System-Simple-1.30/t/13_exports.t0000644000175000017500000000027313612375531017040 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 1; use IPC::System::Simple qw( run runx system systemx capture capturex $EXITVAL EXIT_ANY ); ok(1, "Exports ok"); IPC-System-Simple-1.30/t/win32.t0000644000175000017500000001152313635537363016003 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More; use File::Basename qw(fileparse); use IPC::System::Simple qw(run capture $EXITVAL capturex); use Config; BEGIN { if ($^O ne "MSWin32") { plan skip_all => "Win32 only tests"; } } # This number needs to fit into an 8 bit integer use constant SMALL_EXIT => 42; # This number needs to fit into a 16 bit integer, but not an 8 bit integer. use constant BIG_EXIT => 1000; # This needs to fit into a 32-bit integer, but not a 16-bit integer. use constant HUGE_EXIT => 100_000; # This command should allow us to exit with a specific value. use constant CMD => join ' ', @{ &IPC::System::Simple::WINDOWS_SHELL }; # These are used in the testing of commands in paths which contain spaces. use constant CMD_WITH_SPACES => 'dir with spaces\hello.exe'; use constant CMD_WITH_SPACES_OUTPUT => "Hello World\n"; plan tests => 37; my $perl_path = $Config{perlpath}; $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; my ($perl_exe, $perl_dir) = fileparse($perl_path); my ($raw_perl) = ($perl_exe =~ /^(.*)\.exe$/); ok($raw_perl, "Have perl executables with and w/o extensions."); chdir("t"); # Check for 16 and 32 bit returns. foreach my $big_exitval (SMALL_EXIT, BIG_EXIT, HUGE_EXIT) { my $exit; # XXX Ideally, we would find a way to test the multi-argument form, too, # but cmd.exe no longer works with that form, because all args are quoted, # and /x/d/c must not be. eval { $exit = run([$big_exitval], CMD . qq{ "exit $big_exitval"}); }; is($@,"","Running with $big_exitval ok"); is($exit,$big_exitval,"$big_exitval exit value"); my $capture; eval { $capture = capture([$big_exitval], CMD . qq{ exit $big_exitval"}); }; is($@,"","Capturing with $big_exitval ok"); is($EXITVAL,$big_exitval,"Capture ok with $big_exitval exit value"); } # As of June 2008, all versions of Perl under Win32 have a bug where # they can execute a command twice if it returns -1 and $! is set # to ENOENT or ENOEXEC before system is called. # TODO: Test to see if we're running on a Perl that stuffers from # this bug. # TODO: Make sure that we *don't* suffer from this bug. # Testing to ensure that our PATH gets respected... $ENV{PATH} = ""; eval { run($perl_exe,"-e1"); }; like($@,qr/failed to start/,"No calling perl when not in path"); eval { capture($perl_exe,"-e1"); }; like($@, qr/failed to start/, "Capture can't find perl when not in path"); eval { run($raw_perl,"-e1"); }; like($@, qr/failed to start/, "Can't find raw perl when not in path, either"); $ENV{PATH} = $perl_dir; run($perl_exe,"-e1"); ok(1,"run found perl in path"); run($raw_perl,"-e1"); ok(1,"run found raw perl in path"); my $capture = capture($perl_exe,"-v"); ok(1,"capture found perl in path"); like($capture, qr/Larry Wall/, "Capture text successful"); $capture = capture($raw_perl,"-v"); ok(1,"capture found raw perl in path"); like($capture, qr/Larry Wall/, "Capture text successful"); $capture = capture("$perl_exe -v"); ok(1,"capture found single-arg perl in path"); like($capture, qr/Larry Wall/, "Single-arg Capture text successful"); $capture = capture("$raw_perl -v"); ok(1,"capture found single-arg raw perl in path"); like($capture, qr/Larry Wall/, "Single-arg Capture text successful"); $ENV{PATH} = "$ENV{SystemRoot};$perl_dir;$ENV{SystemRoot}\\System32"; run($perl_exe,"-e1"); ok(1,"perl found in multi-part path"); run($raw_perl,"-e1"); ok(1,"raw perl found in multi-part path"); # RT #48319 - capture/capturex could break STDOUT when running # unknown commands. The following spawns another process to # use capture. In buggy versions, the '2' is never printed. # In bugfixed versions, it is. my $output = capture( $^X, '-MIPC::System::Simple=capture', '-e', q(print 1; eval { capture(q(nosuchcmd)); }; print 2; exit 0;) ); is($output,"12","RT #48319 - Check for STDOUT replumbing"); SKIP: { skip("Inconsistent results between AppVeyor and CPANtesters", 8) unless $ENV{AUTHOR_TESTING}; # Check to ensure we can run commands that include spaces. $output = eval { capturex(CMD_WITH_SPACES, 'ignore'); }; is($@, "", "command with spaces should not error (capturex multi)"); is($output, CMD_WITH_SPACES_OUTPUT, "...and give correct output"); $output = eval { capturex(CMD_WITH_SPACES); }; is($@, "", "command with spaces should not error (capturex single)"); is($output, CMD_WITH_SPACES_OUTPUT, "...and give correct output"); $output = eval { capture(CMD_WITH_SPACES, 'ignore'); }; is($@, "", "command with spaces should not error (capture multi)"); is($output, CMD_WITH_SPACES_OUTPUT, "...and give correct output"); $output = eval { capture('"' . CMD_WITH_SPACES . '"'); }; is($@, "", "command with spaces should not error (capture quoted)"); is($output, CMD_WITH_SPACES_OUTPUT, "...and give correct output"); } # End SKIP block IPC-System-Simple-1.30/t/internal.t0000644000175000017500000000120413612375531016640 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 3; use IPC::System::Simple; # These tests are for testing internal subroutines, and may change # in the future. *_check_exit = \&IPC::System::Simple::_check_exit; is(_check_exit("command",1,[0..5]), 1, "Successful exit"); eval { _check_exit("command",127,[0..5], 1); }; like($@,qr{unexpectedly returned exit value},"Failed exit"); SKIP: { skip("Non-Win32 only", 1) if IPC::System::Simple::WINDOWS; # _spawn_or_die should croak on non-Windows systems. eval { IPC::System::Simple::_spawn_or_die(); }; like($@, qr{Internal error},"_spawn_or_die fails under non-Win32"); }; IPC-System-Simple-1.30/t/04_capture.t0000644000175000017500000000265213612375531017002 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 12; use Config; use constant NO_SUCH_CMD => "this_command_had_better_not_exist"; # We want to invoke our sub-commands using Perl. my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } # Win32 systems don't support multi-arg pipes. Our # simple captures will begin with single-arg tests. my $output_exe = "$perl_path output.pl"; use_ok("IPC::System::Simple","capture"); chdir("t"); # Scalar capture my $output = capture($output_exe); ok(1); is($output,"Hello\nGoodbye\n","Scalar capture"); is($/,"\n","IFS intact"); my $qx_output = qx($output_exe); is($output, $qx_output, "capture and qx() return same results"); # List capture my @output = capture($output_exe); ok(1); is_deeply(\@output,["Hello\n", "Goodbye\n"],"List capture"); is($/,"\n","IFS intact"); my $no_output; eval { $no_output = capture(NO_SUCH_CMD); }; like($@,qr/failed to start/, "failed capture"); is($no_output,undef, "No output from failed command"); # The following is to try and catch weird buffering issues # as we move around filehandles inside capture(). print "# buffer test string"; # NB, no trailing newline $output = capture($output_exe); print "\n"; # Terminates our test string above in TAP output like($output,qr{Hello},"Single-arg capture still works"); unlike($output,qr{buffer test},"No unflushed data readback"); IPC-System-Simple-1.30/t/01_load.t0000644000175000017500000000021013612375531016237 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test; BEGIN { plan tests => 1 }; use IPC::System::Simple; ok(1); # If we made it this far, we're ok. IPC-System-Simple-1.30/t/not_an_exe.txt0000644000175000017500000000010313612375531017514 0ustar jkeenanjkeenanYou can't execute this file, but it is used for some author tests. IPC-System-Simple-1.30/t/output.pl0000755000175000017500000000024213612375531016540 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; # Prints a simple greeting. # Exits with the argument provided, or 0 by default. print "Hello\nGoodbye\n"; exit($ARGV[0] || 0); IPC-System-Simple-1.30/t/02_exit.t0000644000175000017500000000213313612375531016300 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 28; use Config; # We want to invoke our sub-commands using Perl. my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } use IPC::System::Simple qw(run EXIT_ANY); chdir("t"); # Ignore return, since we may already be in t/ run($perl_path,"exiter.pl",0); ok(1,"Multi-arg implicit zero allowed"); foreach (1..5,250..255) { eval { run($perl_path,"exiter.pl",$_); }; like($@, qr/unexpectedly returned exit value $_/ ); } # Single arg tests run("$perl_path exiter.pl 0"); ok(1,"Implicit zero allowed"); foreach (1..5,250..255) { eval { run("$perl_path exiter.pl $_"); }; like($@, qr/unexpectedly returned exit value $_/ ); } # Testing allowable return values run([0], "$perl_path exiter.pl 0"); ok(1,"Explcit zero allowed"); run([1], "$perl_path exiter.pl 1"); ok(1,"Explicit allow of exit status 1"); run([-1], "$perl_path exiter.pl 5"); ok(1,"Exit-all emulation via [-1] allowed"); run(EXIT_ANY, "$perl_path exiter.pl 5"); ok(1,"Exit-all via EXIT_ANY constant"); IPC-System-Simple-1.30/t/05_multi_capture.t0000644000175000017500000000363213612375531020214 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Config; use Test::More; use constant NO_SUCH_CMD => "this_command_had_better_not_exist_either"; use constant NOT_AN_EXE => "not_an_exe.txt"; plan tests => 14; # We want to invoke our sub-commands using Perl. my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } use_ok("IPC::System::Simple","capture"); chdir("t"); # The tests below for $/ are left in, even though IPC::System::Simple # never touches $/ # Scalar capture my $output = capture($perl_path,"output.pl",0); ok(1); is($output,"Hello\nGoodbye\n","Scalar capture"); is($/,"\n",'$/ intact'); # List capture my @output = capture($perl_path,"output.pl",0); ok(1); is_deeply(\@output,["Hello\n", "Goodbye\n"],"List capture"); is($/,"\n",'$/ intact'); # List capture with odd $/ { local $/ = "e"; my @odd_output = capture($perl_path,"output.pl",0); ok(1); is_deeply(\@odd_output,["He","llo\nGoodbye","\n"], 'Odd $/ capture'); } my $no_output; eval { $no_output = capture(NO_SUCH_CMD,1); }; like($@,qr/failed to start/, "failed capture"); is($no_output,undef, "No output from failed command"); # Running Perl -v my $perl_output = capture($perl_path,"-v"); like($perl_output, qr{Larry Wall}, "perl -v contains Larry"); SKIP: { # Considering making these tests depend upon the OS, # as well as $ENV{AUTHOR_TEST}, since different systems # will have different ways of expressing their displeasure # at executing a file that's not executable. skip('Author test. Set $ENV{TEST_AUTHOR} to true to run', 2) unless $ENV{TEST_AUTHOR}; chmod(0,NOT_AN_EXE); eval { capture(NOT_AN_EXE,1); }; chmod(0644,NOT_AN_EXE); # To stop git complaining like($@, qr{Permission denied|No such file|The system cannot find the file specified}, "Permission denied on non-exe" ); like($@, qr{failed to start}, "Non-exe failed to start" ); } IPC-System-Simple-1.30/t/signaler.pl0000755000175000017500000000040413612375531017004 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use warnings; # This program always zaps itself with the signal specified. Perfect # for testing. ;) my $signal_number = shift(@ARGV) || 0; kill($signal_number, $$); exit(1); # Exit failure if the signal wasn't very scary. IPC-System-Simple-1.30/t/10_formatting.t0000644000175000017500000000141613612375531017503 0ustar jkeenanjkeenan#!/usr/bin/perl -wT use strict; use Test::More tests => 5; use_ok("IPC::System::Simple","run"); # A formatting bug caused ISS to mention its name twice in # diagnostics. These tests make sure it's fixed. eval { run($^X); }; like($@,qr{^IPC::System::Simple::run called with tainted argument},"Taint pkg only once"); eval { run(1); }; like($@,qr{^IPC::System::Simple::run called with tainted environment},"Taint env only once"); # Delete everything in %ENV so we can't get taint errors. my @keys = keys %ENV; delete $ENV{$_} foreach @keys; eval { run(); }; like($@,qr{^IPC::System::Simple::run called with no arguments},"Package mentioned only once"); eval { run([0]); }; like($@,qr{^IPC::System::Simple::run called with no command},"Package mentioned only once"); IPC-System-Simple-1.30/t/07_taint.t0000644000175000017500000000331713612721641016455 0ustar jkeenanjkeenan#!/usr/bin/perl -wT use strict; use Test::More tests => 13; use Scalar::Util qw(tainted); use Config; my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } ok(! tainted($perl_path), '$perl_path is clean'); use_ok("IPC::System::Simple","run","capture"); chdir("t"); # Ignore return, since we may already be in t/ my $taint = $0 . "foo"; # ."foo" to avoid zero length ok(tainted($taint),"Sanity - executable name is tainted"); my $evil_zero = 1 - (length($taint) / length($taint)); ok(tainted($evil_zero),"Sanity - Evil zero is tainted"); is($evil_zero,"0","Sanity - Evil zero is still zero"); SKIP: { skip('$ENV{PATH} is clean',2) unless tainted $ENV{PATH}; eval { run("$perl_path exiter.pl 0"); }; like($@,qr{called with tainted environment},"Single-arg, tainted ENV"); eval { run($perl_path, "exiter.pl", 0); }; like($@,qr{called with tainted environment},"Multi-arg, tainted ENV"); } delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV PERL5SHELL DCL$PATH)}; eval { run("$perl_path exiter.pl $evil_zero"); }; like($@,qr{called with tainted argument},"Single-arg, tainted data"); eval { run($perl_path, "exiter.pl", $evil_zero); }; like($@,qr{called with tainted argument},"multi-arg, tainted data"); eval { run("$perl_path exiter.pl 0"); }; is($@, "", "Single-arg, clean data and ENV"); eval { run($perl_path, "exiter.pl", 0); }; is($@, "", "Multi-arg, clean data and ENV"); my $data = eval { capture($perl_path, "exiter.pl", 0) }; ok(tainted($data), "Returns of multi-arg capture should be tainted"); $data = eval { capture("$perl_path exiter.pl 0") }; ok(tainted($data), "Returns of single-arg capture should be tainted"); IPC-System-Simple-1.30/t/09_system.t0000644000175000017500000000146113612375531016665 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More tests => 24; use Config; # We want to invoke our sub-commands using Perl. my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } use IPC::System::Simple qw(system); chdir("t"); # Ignore return, since we may already be in t/ system($perl_path,"exiter.pl",0); ok(1,"Multi-arg system"); system("$perl_path exiter.pl 0"); ok(1,"Single-arg system success"); foreach (1..5,250..255) { eval { system($perl_path,"exiter.pl",$_); }; like($@, qr/unexpectedly returned exit value $_/, "Multi-arg system fail"); } # Single arg tests foreach (1..5,250..255) { eval { system("$perl_path exiter.pl $_"); }; like($@, qr/unexpectedly returned exit value $_/, "Single-arg system fail" ); } IPC-System-Simple-1.30/t/exiter.pl0000755000175000017500000000027013612375531016501 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use warnings; # This program always exits with the value supplied. Perfect # for testing. ;) my $exit_value = shift(@ARGV) || 0; exit($exit_value); IPC-System-Simple-1.30/t/11_newlines.t0000644000175000017500000000127713612375531017163 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use IPC::System::Simple qw(run capture); use Config; use Test::More tests => 6; my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } eval { run( "$perl_path -e1" ) }; is($@, "", 'Run works with single arg'); eval { run( "$perl_path -e1\n" ) }; is($@, "", 'Run works with \\n'); eval { run( "$perl_path -e1\r\n") }; is($@, "", 'Run works with \r\n'); eval { capture( "$perl_path -e1" ) }; is($@, "", 'Run works with single arg'); eval { capture( "$perl_path -e1\n" ) }; is($@, "", 'Run works with \\n'); eval { capture( "$perl_path -e1\r\n") }; is($@, "", 'Run works with \r\n'); IPC-System-Simple-1.30/t/14_uninitialised.t0000644000175000017500000000071613612375531020200 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use warnings; use Test::More; use IPC::System::Simple qw(systemx); eval "use Test::NoWarnings qw(had_no_warnings clear_warnings)"; plan skip_all => "Test::NoWarnings required for testing undef warnings" if $@; plan 'no_plan'; # Passing undef to system functions should produce a nice message, # not a warning and a malformed message. eval { systemx(undef,1); }; like($@, qr/undef/, "systemx() should check for undef"); IPC-System-Simple-1.30/t/08_core.t0000644000175000017500000000206213612375531016266 0ustar jkeenanjkeenan#!/usr/bin/perl -w use strict; use Test::More; use Config; use constant SIGABRT => 6; # Core dumps on OS X are complicated. See GH #5. BEGIN { if ($^O eq 'darwin') { plan skip_all => "Coredump tests skipped under OS X/Darwin"; } } BEGIN { eval { require BSD::Resource; BSD::Resource->import() }; if ($@) { plan skip_all => "BSD::Resource required for coredump tests"; } } plan tests => 3; # We want to invoke our sub-commands using Perl. my $perl_path = $Config{perlpath}; if ($^O ne 'VMS') { $perl_path .= $Config{_exe} unless $perl_path =~ m/$Config{_exe}$/i; } use_ok("IPC::System::Simple","run"); chdir("t"); my $rlimit_success = setrlimit(RLIMIT_CORE, RLIM_INFINITY, RLIM_INFINITY); SKIP: { skip "setrlimit failed", 2 if not $rlimit_success; eval { run([1],$perl_path, 'signaler.pl', SIGABRT); }; like($@, qr/died to signal/, "Signal caught, \$? = $?"); like($@, qr/dumped core/, "Coredump caught, \$? = $?"); unlink('core'); # Clean up our core file, if it exists. } IPC-System-Simple-1.30/lib/0000755000175000017500000000000013636261620015144 5ustar jkeenanjkeenanIPC-System-Simple-1.30/lib/IPC/0000755000175000017500000000000013636261620015557 5ustar jkeenanjkeenanIPC-System-Simple-1.30/lib/IPC/System/0000755000175000017500000000000013636261620017043 5ustar jkeenanjkeenanIPC-System-Simple-1.30/lib/IPC/System/Simple.pm0000644000175000017500000010216513636260651020642 0ustar jkeenanjkeenanpackage IPC::System::Simple; # ABSTRACT: Run commands simply, with detailed diagnostics use 5.006; use strict; use warnings; use re 'taint'; use Carp; use List::Util qw(first); use Scalar::Util qw(tainted); use Config; use constant WINDOWS => ($^O eq 'MSWin32'); use constant VMS => ($^O eq 'VMS'); BEGIN { # It would be lovely to use the 'if' module here, but it didn't # enter core until 5.6.2, and we want to keep 5.6.0 compatibility. if (WINDOWS) { ## no critic (ProhibitStringyEval) eval q{ use Win32::Process qw(INFINITE NORMAL_PRIORITY_CLASS); use File::Spec; use Win32; use Win32::ShellQuote; # This uses the same rules as the core win32.c/get_shell() call. use constant WINDOWS_SHELL => eval { Win32::IsWinNT() } ? [ File::Spec->catfile(Win32::GetFolderPath(Win32::CSIDL_SYSTEM), 'cmd.exe'), '/x/d/c' ] : [ File::Spec->catfile(Win32::GetFolderPath(Win32::CSIDL_SYSTEM), 'command.com'), '/c' ]; # These are used when invoking _win32_capture use constant NO_SHELL => 0; use constant USE_SHELL => 1; }; ## use critic # Die nosily if any of the above broke. die $@ if $@; } } # Note that we don't use WIFSTOPPED because perl never uses # the WUNTRACED flag, and hence will never return early from # system() if the child processes is suspended with a SIGSTOP. use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); use constant FAIL_START => q{"%s" failed to start: "%s"}; use constant FAIL_PLUMBING => q{Error in IPC::System::Simple plumbing: "%s" - "%s"}; use constant FAIL_CMD_BLANK => q{Entirely blank command passed: "%s"}; use constant FAIL_INTERNAL => q{Internal error in IPC::System::Simple: "%s"}; use constant FAIL_TAINT => q{%s called with tainted argument "%s"}; use constant FAIL_TAINT_ENV => q{%s called with tainted environment $ENV{%s}}; use constant FAIL_SIGNAL => q{"%s" died to signal "%s" (%d)%s}; use constant FAIL_BADEXIT => q{"%s" unexpectedly returned exit value %d}; use constant FAIL_UNDEF => q{%s called with undefined command}; use constant FAIL_POSIX => q{IPC::System::Simple does not understand the POSIX error '%s'. Please check https://metacpan.org/pod/IPC::System::Simple to see if there is an updated version. If not please report this as a bug to https://github.com/pjf/ipc-system-simple/issues}; # On Perl's older than 5.8.x we can't assume that there'll be a # $^{TAINT} for us to check, so we assume that our args may always # be tainted. use constant ASSUME_TAINTED => ($] < 5.008); use constant EXIT_ANY_CONST => -1; # Used internally use constant EXIT_ANY => [ EXIT_ANY_CONST ]; # Exported use constant UNDEFINED_POSIX_RE => qr{not (?:defined|a valid) POSIX macro|not implemented on this architecture}; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( capture capturex run runx system systemx $EXITVAL EXIT_ANY ); our $VERSION = '1.30'; $VERSION =~ tr/_//d; our $EXITVAL = -1; my @Signal_from_number = split(' ', $Config{sig_name}); # Environment variables we don't want to see tainted. my @Check_tainted_env = qw(PATH IFS CDPATH ENV BASH_ENV); if (WINDOWS) { push(@Check_tainted_env, 'PERL5SHELL'); } if (VMS) { push(@Check_tainted_env, 'DCL$PATH'); } # Not all systems implement the WIFEXITED calls, but POSIX # will always export them (even if they're just stubs that # die with an error). Test for the presence of a working # WIFEXITED and friends, or define our own. eval { WIFEXITED(0); }; if ($@ =~ UNDEFINED_POSIX_RE) { no warnings 'redefine'; ## no critic *WIFEXITED = sub { not $_[0] & 0xff }; *WEXITSTATUS = sub { $_[0] >> 8 }; *WIFSIGNALED = sub { $_[0] & 127 }; *WTERMSIG = sub { $_[0] & 127 }; } elsif ($@) { croak sprintf FAIL_POSIX, $@; } # None of the POSIX modules I've found define WCOREDUMP, although # many systems define it. Check the POSIX module in the hope that # it may actually be there. # TODO: Ideally, $NATIVE_WCOREDUMP should be a constant. my $NATIVE_WCOREDUMP; eval { POSIX::WCOREDUMP(1); }; if ($@ =~ UNDEFINED_POSIX_RE) { *WCOREDUMP = sub { $_[0] & 128 }; $NATIVE_WCOREDUMP = 0; } elsif ($@) { croak sprintf FAIL_POSIX, $@; } else { # POSIX actually has it defined! Huzzah! *WCOREDUMP = \&POSIX::WCOREDUMP; $NATIVE_WCOREDUMP = 1; } sub _native_wcoredump { return $NATIVE_WCOREDUMP; } # system simply calls run no warnings 'once'; ## no critic *system = \&run; *systemx = \&runx; use warnings; # run is our way of running a process with system() semantics sub run { _check_taint(@_); my ($valid_returns, $command, @args) = _process_args(@_); # If we have arguments, we really want to call systemx, # so we do so. if (@args) { return systemx($valid_returns, $command, @args); } if (WINDOWS) { my $pid = _spawn_or_die(&WINDOWS_SHELL->[0], join ' ', @{&WINDOWS_SHELL}, $command); $pid->Wait(INFINITE); # Wait for process exit. $pid->GetExitCode($EXITVAL); return _check_exit($command,$EXITVAL,$valid_returns); } # Without arguments, we're calling system, and checking # the results. # We're throwing our own exception on command not found, so # we don't need a warning from Perl. { # silence 'Statement unlikely to be reached' warning no warnings 'exec'; ## no critic CORE::system($command,@args); } return _process_child_error($?,$command,$valid_returns); } # runx is just like system/run, but *never* invokes the shell. sub runx { _check_taint(@_); my ($valid_returns, $command, @args) = _process_args(@_); if (WINDOWS) { our $EXITVAL = -1; my $pid = _spawn_or_die($command, Win32::ShellQuote::quote_native($command, @args)); $pid->Wait(INFINITE); # Wait for process exit. $pid->GetExitCode($EXITVAL); return _check_exit($command,$EXITVAL,$valid_returns); } # If system() fails, we throw our own exception. We don't # need to have perl complain about it too. no warnings; ## no critic CORE::system { $command } $command, @args; return _process_child_error($?, $command, $valid_returns); } # capture is our way of running a process with backticks/qx semantics sub capture { _check_taint(@_); my ($valid_returns, $command, @args) = _process_args(@_); if (@args) { return capturex($valid_returns, $command, @args); } if (WINDOWS) { # USE_SHELL really means "You may use the shell if you need it." return _win32_capture(USE_SHELL, $valid_returns, $command); } our $EXITVAL = -1; my $wantarray = wantarray(); # We'll produce our own warnings on failure to execute. no warnings 'exec'; ## no critic if ($wantarray) { my @results = qx($command); _process_child_error($?,$command,$valid_returns); return @results; } my $results = qx($command); _process_child_error($?,$command,$valid_returns); return $results; } # _win32_capture implements the capture and capurex commands on Win32. # We need to wrap the whole internals of this sub into # an if (WINDOWS) block to avoid it being compiled on non-Win32 systems. sub _win32_capture { if (not WINDOWS) { croak sprintf(FAIL_INTERNAL, "_win32_capture called when not under Win32"); } else { my ($use_shell, $valid_returns, $command, @args) = @_; my $wantarray = wantarray(); # Perl doesn't support multi-arg open under # Windows. Perl also doesn't provide very good # feedback when normal backtails fail, either; # it returns exit status from the shell # (which is indistinguishable from the command # running and producing the same exit status). # As such, we essentially have to write our own # backticks. # We start by dup'ing STDOUT. open(my $saved_stdout, '>&', \*STDOUT) ## no critic or croak sprintf(FAIL_PLUMBING, "Can't dup STDOUT", $!); # We now open up a pipe that will allow us to # communicate with the new process. pipe(my ($read_fh, $write_fh)) or croak sprintf(FAIL_PLUMBING, "Can't create pipe", $!); # Allow CRLF sequences to become "\n", since # this is what Perl backticks do. binmode($read_fh, ':crlf'); # Now we re-open our STDOUT to $write_fh... open(STDOUT, '>&', $write_fh) ## no critic or croak sprintf(FAIL_PLUMBING, "Can't redirect STDOUT", $!); # If we have args, or we're told not to use the shell, then # we treat $command as our shell. Otherwise we grub around # in our command to look for a command to run. # # Note that we don't actually *use* the shell (although in # a future version we might). Being told not to use the shell # (capturex) means we treat our command as really being a command, # and not a command line. my $exe = @args ? $command : (! $use_shell) ? $command : $command =~ m{^"([^"]+)"}x ? $1 : $command =~ m{(\S+) }x ? $1 : croak sprintf(FAIL_CMD_BLANK, $command); # And now we spawn our new process with inherited # filehandles. my $err; my $pid = eval { _spawn_or_die($exe, @args ? Win32::ShellQuote::quote_native($command, @args) : $command); } or do { $err = $@; }; # Regardless of whether our command ran, we must restore STDOUT. # RT #48319 open(STDOUT, '>&', $saved_stdout) ## no critic or croak sprintf(FAIL_PLUMBING,"Can't restore STDOUT", $!); # And now, if there was an actual error , propagate it. die $err if defined $err; # If there's an error from _spawn_or_die # Clean-up the filehandles we no longer need... close($write_fh) or croak sprintf(FAIL_PLUMBING,q{Can't close write end of pipe}, $!); close($saved_stdout) or croak sprintf(FAIL_PLUMBING,q{Can't close saved STDOUT}, $!); # Read the data from our child... my (@results, $result); if ($wantarray) { @results = <$read_fh>; } else { $result = join("",<$read_fh>); } # Tidy up our windows process and we're done! $pid->Wait(INFINITE); # Wait for process exit. $pid->GetExitCode($EXITVAL); _check_exit($command,$EXITVAL,$valid_returns); return $wantarray ? @results : $result; } } # capturex() is just like backticks/qx, but never invokes the shell. sub capturex { _check_taint(@_); my ($valid_returns, $command, @args) = _process_args(@_); our $EXITVAL = -1; my $wantarray = wantarray(); if (WINDOWS) { return _win32_capture(NO_SHELL, $valid_returns, $command, @args); } # We can't use a multi-arg piped open here, since 5.6.x # doesn't like them. Instead we emulate what 5.8.x does, # which is to create a pipe(), set the close-on-exec flag # on the child, and the fork/exec. If the exec fails, the # child writes to the pipe. If the exec succeeds, then # the pipe closes without data. pipe(my ($read_fh, $write_fh)) or croak sprintf(FAIL_PLUMBING, "Can't create pipe", $!); # This next line also does an implicit fork. my $pid = open(my $pipe, '-|'); ## no critic if (not defined $pid) { croak sprintf(FAIL_START, $command, $!); } elsif (not $pid) { # Child process, execs command. close($read_fh); # TODO: 'no warnings exec' doesn't get rid # of the 'unlikely to be reached' warnings. # This is a bug in perl / perldiag / perllexwarn / warnings. no warnings; ## no critic CORE::exec { $command } $command, @args; # Oh no, exec fails! Send the reason why to # the parent. print {$write_fh} int($!); exit(-1); } { # In parent process. close($write_fh); # Parent process, check for child error. my $error = <$read_fh>; # Tidy up our pipes. close($read_fh); # Check for error. if ($error) { # Setting $! to our child error number gives # us nice looking strings when printed. local $! = $error; croak sprintf(FAIL_START, $command, $!); } } # Parent process, we don't care about our pid, but we # do go and read our pipe. if ($wantarray) { my @results = <$pipe>; close($pipe); _process_child_error($?,$command,$valid_returns); return @results; } # NB: We don't check the return status on close(), since # on failure it sets $?, which we then inspect for more # useful information. my $results = join("",<$pipe>); close($pipe); _process_child_error($?,$command,$valid_returns); return $results; } # Tries really hard to spawn a process under Windows. Returns # the pid on success, or undef on error. sub _spawn_or_die { # We need to wrap practically the entire sub in an # if block to ensure it doesn't get compiled under non-Win32 # systems. Compiling on these systems would not only be a # waste of time, but also results in complaints about # the NORMAL_PRIORITY_CLASS constant. if (not WINDOWS) { croak sprintf(FAIL_INTERNAL, "_spawn_or_die called when not under Win32"); } else { my ($orig_exe, $cmdline) = @_; my $pid; my $exe = $orig_exe; # If our command doesn't have an extension, add one. $exe .= $Config{_exe} if ($exe !~ m{\.}); Win32::Process::Create( $pid, $exe, $cmdline, 1, NORMAL_PRIORITY_CLASS, "." ) and return $pid; my @path = split(/;/,$ENV{PATH}); foreach my $dir (@path) { my $fullpath = File::Spec->catfile($dir,$exe); # We're using -x here on the assumption that stat() # is faster than spawn, so trying to spawn a process # for each path element will be unacceptably # inefficient. if (-x $fullpath) { Win32::Process::Create( $pid, $fullpath, $cmdline, 1, NORMAL_PRIORITY_CLASS, "." ) and return $pid; } } croak sprintf(FAIL_START, $orig_exe, $^E); } } # Complain on tainted arguments or environment. # ASSUME_TAINTED is true for 5.6.x, since it's missing ${^TAINT} sub _check_taint { return if not (ASSUME_TAINTED or ${^TAINT}); my $caller = (caller(1))[3]; foreach my $var (@_) { if (tainted $var) { croak sprintf(FAIL_TAINT, $caller, $var); } } foreach my $var (@Check_tainted_env) { if (tainted $ENV{$var} ) { croak sprintf(FAIL_TAINT_ENV, $caller, $var); } } return; } # This subroutine performs the difficult task of interpreting # $?. It's not intended to be called directly, as it will # croak on errors, and its implementation and interface may # change in the future. sub _process_child_error { my ($child_error, $command, $valid_returns) = @_; $EXITVAL = -1; my $coredump = WCOREDUMP($child_error); # There's a bug in perl 5.8.9 and 5.10.0 where if the system # does not provide a native WCOREDUMP, then $? will # never contain coredump information. This code # checks to see if we have the bug, and works around # it if needed. if ($] >= 5.008009 and not $NATIVE_WCOREDUMP) { $coredump ||= WCOREDUMP( ${^CHILD_ERROR_NATIVE} ); } if ($child_error == -1) { croak sprintf(FAIL_START, $command, $!); } elsif ( WIFEXITED( $child_error ) ) { $EXITVAL = WEXITSTATUS( $child_error ); return _check_exit($command,$EXITVAL,$valid_returns); } elsif ( WIFSIGNALED( $child_error ) ) { my $signal_no = WTERMSIG( $child_error ); my $signal_name = $Signal_from_number[$signal_no] || "UNKNOWN"; croak sprintf FAIL_SIGNAL, $command, $signal_name, $signal_no, ($coredump ? " and dumped core" : ""); } croak sprintf(FAIL_INTERNAL, qq{'$command' ran without exit value or signal}); } # A simple subroutine for checking exit values. Results in better # assurance of consistent error messages, and better forward support # for new features in I::S::S. sub _check_exit { my ($command, $exitval, $valid_returns) = @_; # If we have a single-value list consisting of the EXIT_ANY # value, then we're happy with whatever exit value we're given. if (@$valid_returns == 1 and $valid_returns->[0] == EXIT_ANY_CONST) { return $exitval; } if (not defined first { $_ == $exitval } @$valid_returns) { croak sprintf FAIL_BADEXIT, $command, $exitval; } return $exitval; } # This subroutine simply determines a list of valid returns, the command # name, and any arguments that we need to pass to it. sub _process_args { my $valid_returns = [ 0 ]; my $caller = (caller(1))[3]; if (not @_) { croak "$caller called with no arguments"; } if (ref $_[0] eq "ARRAY") { $valid_returns = shift(@_); } if (not @_) { croak "$caller called with no command"; } my $command = shift(@_); if (not defined $command) { croak sprintf( FAIL_UNDEF, $caller ); } return ($valid_returns,$command,@_); } 1; __END__ =head1 NAME IPC::System::Simple - Run commands simply, with detailed diagnostics =head1 SYNOPSIS use IPC::System::Simple qw(system systemx capture capturex); system("some_command"); # Command succeeds or dies! system("some_command",@args); # Succeeds or dies, avoids shell if @args systemx("some_command",@args); # Succeeds or dies, NEVER uses the shell # Capture the output of a command (just like backticks). Dies on error. my $output = capture("some_command"); # Just like backticks in list context. Dies on error. my @output = capture("some_command"); # As above, but avoids the shell if @args is non-empty my $output = capture("some_command", @args); # As above, but NEVER invokes the shell. my $output = capturex("some_command", @args); my @output = capturex("some_command", @args); =head1 DESCRIPTION Calling Perl's in-built C function is easy, determining if it was successful is I. Let's face it, C<$?> isn't the nicest variable in the world to play with, and even if you I check it, producing a well-formatted error string takes a lot of work. C takes the hard work out of calling external commands. In fact, if you want to be really lazy, you can just write: use IPC::System::Simple qw(system); and all of your C commands will either succeed (run to completion and return a zero exit value), or die with rich diagnostic messages. The C module also provides a simple replacement to Perl's backticks operator. Simply write: use IPC::System::Simple qw(capture); and then use the L command just like you'd use backticks. If there's an error, it will die with a detailed description of what went wrong. Better still, you can even use C to run the equivalent of backticks, but without the shell: use IPC::System::Simple qw(capturex); my $result = capturex($command, @args); If you want more power than the basic interface, including the ability to specify which exit values are acceptable, trap errors, or process diagnostics, then read on! =head1 ADVANCED SYNOPSIS use IPC::System::Simple qw( capture capturex system systemx run runx $EXITVAL EXIT_ANY ); # Run a command, throwing exception on failure run("some_command"); runx("some_command",@args); # Run a command, avoiding the shell # Do the same thing, but with the drop-in system replacement. system("some_command"); systemx("some_command", @args); # Run a command which must return 0..5, avoid the shell, and get the # exit value (we could also look at $EXITVAL) my $exit_value = runx([0..5], "some_command", @args); # The same, but any exit value will do. my $exit_value = runx(EXIT_ANY, "some_command", @args); # Capture output into $result and throw exception on failure my $result = capture("some_command"); # Check exit value from captured command print "some_command exited with status $EXITVAL\n"; # Captures into @lines, splitting on $/ my @lines = capture("some_command"); # Run a command which must return 0..5, capture the output into # @lines, and avoid the shell. my @lines = capturex([0..5], "some_command", @args); =head1 ADVANCED USAGE =head2 run() and system() C provides a subroutine called C, that executes a command using the same semantics as Perl's built-in C: use IPC::System::Simple qw(run); run("cat *.txt"); # Execute command via the shell run("cat","/etc/motd"); # Execute command without shell The primary difference between Perl's in-built system and the C command is that C will throw an exception on failure, and allows a list of acceptable exit values to be set. See L for further information. In fact, you can even have C replace the default C function for your package so it has the same behaviour: use IPC::System::Simple qw(system); system("cat *.txt"); # system now succeeds or dies! C and C are aliases to each other. See also L for variants of C and C that never invoke the shell, even with a single argument. =head2 capture() A second subroutine, named C executes a command with the same semantics as Perl's built-in backticks (and C): use IPC::System::Simple qw(capture); # Capture text while invoking the shell. my $file = capture("cat /etc/motd"); my @lines = capture("cat /etc/passwd"); However unlike regular backticks, which always use the shell, C will bypass the shell when called with multiple arguments: # Capture text while avoiding the shell. my $file = capture("cat", "/etc/motd"); my @lines = capture("cat", "/etc/passwd"); See also L for a variant of C that never invokes the shell, even with a single argument. =head2 runx(), systemx() and capturex() The C, C and C commands are identical to the multi-argument forms of C, C and C respectively, but I invoke the shell, even when called with a single argument. These forms are particularly useful when a command's argument list I be empty, for example: systemx($cmd, @args); The use of C here guarantees that the shell will I be invoked, even if C<@args> is empty. =head2 Exception handling In the case where the command returns an unexpected status, both C and C will throw an exception, which if not caught will terminate your program with an error. Capturing the exception is easy: eval { run("cat *.txt"); }; if ($@) { print "Something went wrong - $@\n"; } See the diagnostics section below for more details. =head3 Exception cases C considers the following to be unexpected, and worthy of exception: =over 4 =item * Failing to start entirely (eg, command not found, permission denied). =item * Returning an exit value other than zero (but see below). =item * Being killed by a signal. =item * Being passed tainted data (in taint mode). =back =head2 Exit values Traditionally, system commands return a zero status for success and a non-zero status for failure. C will default to throwing an exception if a non-zero exit value is returned. You may specify a range of values which are considered acceptable exit values by passing an I as the first argument. The special constant C can be used to allow I exit value to be returned. use IPC::System::Simple qw(run system capture EXIT_ANY); run( [0..5], "cat *.txt"); # Exit values 0-5 are OK system( [0..5], "cat *.txt"); # This works the same way my @lines = capture( EXIT_ANY, "cat *.txt"); # Any exit is fine. The C and replacement C subroutines returns the exit value of the process: my $exit_value = run( [0..5], "cat *.txt"); # OR: my $exit_value = system( [0..5] "cat *.txt"); print "Program exited with value $exit_value\n"; =head3 $EXITVAL The exit value of any command executed by C can always be retrieved from the C<$IPC::System::Simple::EXITVAL> variable: This is particularly useful when inspecting results from C, which returns the captured text from the command. use IPC::System::Simple qw(capture $EXITVAL EXIT_ANY); my @enemies_defeated = capture(EXIT_ANY, "defeat_evil", "/dev/mordor"); print "Program exited with value $EXITVAL\n"; C<$EXITVAL> will be set to C<-1> if the command did not exit normally (eg, being terminated by a signal) or did not start. In this situation an exception will also be thrown. =head2 WINDOWS-SPECIFIC NOTES The C subroutine make available the full 32-bit exit value on Win32 systems. This has been true since C v0.06 when called with multiple arguments, and since v1.25 when called with a single argument. This is different from the previous versions of C and from Perl's in-build C function, which can only handle 8-bit return values. The C subroutine always returns the 32-bit exit value under Windows. The C subroutine also never uses the shell, even when passed a single argument. The C subroutine always uses a shell when passed a single argument. On NT systems, it uses C in the system root, and on non-NT systems it uses C in the system root. As of C v1.25, the C and C subroutines, as well as multiple-argument calls to the C and C subroutines, have their arguments properly quoted, so that arugments with spaces and the like work properly. Unfortunately, this breaks any attempt to invoke the shell itself. If you really need to execute C or C, use the single-argument form. For single-argument calls to C and C, the argument must be properly shell-quoted in advance of the call. Versions of C before v0.09 would not search the C environment variable when the multi-argument form of C was called. Versions from v0.09 onwards correctly search the path provided the command is provided including the extension (eg, C rather than just C, or C rather than just C). If no extension is provided, C<.exe> is assumed. Signals are not supported on Windows systems. Sending a signal to a Windows process will usually cause it to exit with the signal number used. =head1 DIAGNOSTICS =over 4 =item "%s" failed to start: "%s" The command specified did not even start. It may not exist, or you may not have permission to use it. The reason it could not start (as determined from C<$!>) will be provided. =item "%s" unexpectedly returned exit value %d The command ran successfully, but returned an exit value we did not expect. The value returned is reported. =item "%s" died to signal "%s" (%d) %s The command was killed by a signal. The name of the signal will be reported, or C if it cannot be determined. The signal number is always reported. If we detected that the process dumped core, then the string C is appended. =item IPC::System::Simple::%s called with no arguments You attempted to call C or C but did not provide any arguments at all. At the very lease you need to supply a command to run. =item IPC::System::Simple::%s called with no command You called C or C with a list of acceptable exit values, but no actual command. =item IPC::System::Simple::%s called with tainted argument "%s" You called C or C with tainted (untrusted) arguments, which is almost certainly a bad idea. To untaint your arguments you'll need to pass your data through a regular expression and use the resulting match variables. See L for more information. =item IPC::System::Simple::%s called with tainted environment $ENV{%s} You called C or C but part of your environment was tainted (untrusted). You should either delete the named environment variable before calling C, or set it to an untainted value (usually one set inside your program). See L for more information. =item Error in IPC::System::Simple plumbing: "%s" - "%s" Implementing the C command involves dark and terrible magicks involving pipes, and one of them has sprung a leak. This could be due to a lack of file descriptors, although there are other possibilities. If you are able to reproduce this error, you are encouraged to submit a bug report according to the L section below. =item Internal error in IPC::System::Simple: "%s" You've found a bug in C. Please check to see if an updated version of C is available. If not, please file a bug report according to the L section below. =item IPC::System::Simple::%s called with undefined command You've passed the undefined value as a command to be executed. While this is a very Zen-like action, it's not supported by Perl's current implementation. =back =head1 DEPENDENCIES This module depends upon L when used on Win32 system. C is bundled as a core module in ActivePerl 5.6 and above. There are no non-core dependencies on non-Win32 systems. =head1 COMPARISON TO OTHER APIs Perl provides a range of in-built functions for handling external commands, and CPAN provides even more. The C differentiates itself from other options by providing: =over 4 =item Extremely detailed diagnostics The diagnostics produced by C are designed to provide as much information as possible. Rather than requiring the developer to inspect C<$?>, C does the hard work for you. If an odd exit status is provided, you're informed of what it is. If a signal kills your process, you are informed of both its name and number. If tainted data or environment prevents your command from running, you are informed of exactly which data or environmental variable is tainted. =item Exceptions on failure C takes an aggressive approach to error handling. Rather than allow commands to fail silently, exceptions are thrown when unexpected results are seen. This allows for easy development using a try/catch style, and avoids the possibility of accidentally continuing after a failed command. =item Easy access to exit status The C, C and C commands all set C<$EXITVAL>, making it easy to determine the exit status of a command. Additionally, the C and C interfaces return the exit status. =item Consistent interfaces When called with multiple arguments, the C, C and C interfaces I invoke the shell. This differs from the in-built Perl C command which may invoke the shell under Windows when called with multiple arguments. It differs from the in-built Perl backticks operator which always invokes the shell. =back =head1 BUGS When C is exported, the exotic form C is not supported. Attemping to use the exotic form is a syntax error. This affects the calling package I. Use C if you need it, or consider using the L module to replace C with lexical scope. Core dumps are only checked for when a process dies due to a signal. It is not believed there are any systems where processes can dump core without dying to a signal. C status is not checked, as perl never spawns processes with the C option. Signals are not supported under Win32 systems, since they don't work at all like Unix signals. Win32 signals cause commands to exit with a given exit value, which this modules I capture. =head2 Reporting bugs Before reporting a bug, please check to ensure you are using the most recent version of C. Your problem may have already been fixed in a new release. You can find the C bug-tracker at L . Please check to see if your bug has already been reported; if in doubt, report yours anyway. Submitting a patch and/or failing test case will greatly expedite the fixing of bugs. =head1 FEEDBACK If you find this module useful, please consider rating it on the CPAN Ratings service at L . The module author loves to hear how C has made your life better (or worse). Feedback can be sent to Epjf@perltraining.com.auE. =head1 SEE ALSO L uses C to provide succeed-or-die replacements to C (and other built-ins) with lexical scope. L, L, L, L, L, L, L =head1 AUTHOR Paul Fenwick Epjf@cpan.orgE =head1 COPYRIGHT AND LICENSE Copyright (C) 2006-2008 by Paul Fenwick This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.6.0 or, at your option, any later version of Perl 5 you may have available. =for Pod::Coverage WCOREDUMP =cut