pax_global_header00006660000000000000000000000064141401542440014511gustar00rootroot0000000000000052 comment=b22dc4f826af8bd12ab5a9bb4a821b5f63c34e52 cronutils-version-1.10/000077500000000000000000000000001414015424400151375ustar00rootroot00000000000000cronutils-version-1.10/.github/000077500000000000000000000000001414015424400164775ustar00rootroot00000000000000cronutils-version-1.10/.github/workflows/000077500000000000000000000000001414015424400205345ustar00rootroot00000000000000cronutils-version-1.10/.github/workflows/ci.yml000066400000000000000000000002451414015424400216530ustar00rootroot00000000000000name: CI on: push: pull_request: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: test run: make test cronutils-version-1.10/.github/workflows/codeql-analysis.yml000066400000000000000000000044651414015424400243600ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '38 5 * * 3' jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: [ 'cpp' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 cronutils-version-1.10/.gitignore000066400000000000000000000002061414015424400171250ustar00rootroot00000000000000runalarm runlock runstat debian/cronutils/* debian/cronutils.substvars debian/cronutils.debhelper.log debian/files debian/patches .pc cronutils-version-1.10/CONTRIBUTING.md000066400000000000000000000025631414015424400173760ustar00rootroot00000000000000Want to contribute? Great! First, read this page (including the small print at the end). ### Before you contribute Before we can use your code, you must sign the [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) (CLA), which you can do online. The CLA is necessary mainly because you own the copyright to your changes, even after your contribution becomes part of our codebase, so we need your permission to use and distribute your code. We also need to be sure of various other things—for instance that you'll tell us if you know that your code infringes on other people's patents. You don't have to sign the CLA until after you've submitted your code for review and a member has approved it, but you must do it before we can put your code into our codebase. Before you start working on a larger contribution, you should get in touch with us first through the issue tracker with your idea so that we can help out and possibly guide you. Coordinating up front makes it much easier to avoid frustration later on. ### Code reviews All submissions, including submissions by project members, require review. We use Github pull requests for this purpose. ### The small print Contributions made by corporations are covered by a different agreement than the one above, the Software Grant and Corporate Contributor License Agreement. cronutils-version-1.10/LICENSE000066400000000000000000000261361414015424400161540ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cronutils-version-1.10/Makefile000066400000000000000000000035261414015424400166050ustar00rootroot00000000000000# Copyright 2010 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. all: runalarm runstat runlock runalarm: runalarm.c subprocess.c runlock: runlock.c subprocess.c tempdir.c runstat: runstat.c subprocess.c tempdir.c CFLAGS+=-Wall -Werror -Wextra -D_XOPEN_SOURCE=500 -g -ansi -pedantic-errors -Wwrite-strings -Wcast-align -Wcast-qual -Winit-self -Wformat=2 -Wuninitialized -Wmissing-declarations -Wpointer-arith -Wstrict-aliasing -fstrict-aliasing LDLIBS+=-lrt SOURCES = runalarm.c runlock.c runstat.c subprocess.c subprocess.h tempdir.c tempdir.h Makefile runalarm.1 runlock.1 runstat.1 version examples cronutils.spec runcron regtest.sh tests prefix = usr/local BINDIR = $(prefix)/bin MANDIR = $(prefix)/share/man/man1 VERSION = $(shell cat version) install: mkdir -p -m 755 $(DESTDIR)/$(BINDIR) $(DESTDIR)/$(MANDIR) install -m 755 runalarm runlock runstat $(DESTDIR)/$(BINDIR) install -m 644 runalarm.1 runlock.1 runstat.1 $(DESTDIR)/$(MANDIR) clean: rm -f runalarm runlock runstat distclean: clean rm -f *~ \#* dist: rm -rf cronutils-$(VERSION) cronutils-$(VERSION).tar cronutils-$(VERSION).tar.gz mkdir cronutils-$(VERSION) cp -r $(SOURCES) cronutils-$(VERSION) tar cf cronutils-$(VERSION).tar cronutils-$(VERSION) gzip -9 cronutils-$(VERSION).tar rm -rf cronutils-$(VERSION) test: all ./regtest.sh .PHONY: dist clean install distclean test cronutils-version-1.10/README.md000066400000000000000000000017261414015424400164240ustar00rootroot00000000000000cronutils - utilities to assist running batch processing jobs ============================================================= ![ci](https://github.com/google/cronutils/workflows/CI/badge.svg) cronutils is a set of tools to assist the reliable running of periodic and batch jobs. * `runalarm`: Limit the running time of a process. * `runlock`: Prevent concurrent runs of a process. * `runstat`: Export statistics about a process's execution. * `runcron`: Simple wrapper around the above tools. Used together, they can be used to specify overrun policies for periodic jobs, for example: * Allow overrun -- let the first job run to completion * Kill older job -- specify a timeout on the older job to limit its execution Additionally, metrics can be exported to your favourite metrics collector at the termination of the job's run, so that abnormal behaviour can be monitored for and alerted on. Mailing list at http://groups.google.com/group/cronutils-users. cronutils-version-1.10/cronutils.spec000066400000000000000000000014531414015424400200400ustar00rootroot00000000000000Name: cronutils Version: 1.1 Release: 1%{?dist} Summary: Utilities to assist running batch processing jobs. Group: System Environment/Base License: ASL 2.0 URL: http://code.google.com/p/cronutils/ Source0: http://cronutils.googlecode.com/files/%{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) %description A set of utilities to complement batch processing jobs, such as those run from cron, by limiting concurrent execution of jobs, setting hard limits on the runtime of a job, and recording execution statistics of a completed job. %prep %setup -q %build make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT prefix=usr %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %{_bindir}/* %{_mandir}/man1/* cronutils-version-1.10/debian/000077500000000000000000000000001414015424400163615ustar00rootroot00000000000000cronutils-version-1.10/debian/changelog000066400000000000000000000056451414015424400202450ustar00rootroot00000000000000cronutils (1.8-1) unstable; urgency=medium * New upstream release. (Closes: #777828) -- Jamie Wilkinson Sat, 14 Mar 2015 22:03:25 +1100 cronutils (1.7-1) unstable; urgency=medium * New upstream release. * Bump standards-version to 3.9.6. -- Jamie Wilkinson Sat, 14 Mar 2015 21:40:30 +1100 cronutils (1.6-1) unstable; urgency=low * New upstream release. -- Jamie Wilkinson Sun, 01 Jun 2014 13:23:33 +1000 cronutils (1.5-3) unstable; urgency=medium * Update the hardening build flags in debian/rules for debhelper 9. -- Jamie Wilkinson Wed, 28 May 2014 18:20:32 +1000 cronutils (1.5-2) unstable; urgency=medium * Add VCS fields to the control file. * Update debian/watch to github format, after upstream move. * Update standards version to 3.9.5. * Convert debian/copyright to the DEP5 machine readable format. * Add debian/gbp.conf to configure git-buildpackage for the VCS. -- Jamie Wilkinson Wed, 28 May 2014 18:03:07 +1000 cronutils (1.5-1) unstable; urgency=low * New upstream release. * Update standards version. -- Jamie Wilkinson Wed, 28 Aug 2013 07:10:36 +1000 cronutils (1.4-3) unstable; urgency=low * Fix build dependency on dpkg-dev. -- Jamie Wilkinson Wed, 09 Jan 2013 10:11:00 +0000 cronutils (1.4-2) unstable; urgency=low * Update Standards-Version to 3.9.2. * Bump debian/compat to 9. * Use buildflags.mk in debian/rules to enable hardening flags. -- Jamie Wilkinson Wed, 09 Jan 2013 19:02:57 +1100 cronutils (1.4-1) unstable; urgency=low * New upstream release. -- Jamie Wilkinson Tue, 08 Jan 2013 11:18:55 +0000 cronutils (1.3.1-1) unstable; urgency=low * New upstream release. -- Jamie Wilkinson Mon, 07 Jan 2013 22:26:39 +0000 cronutils (1.3-1) unstable; urgency=low * New upstream release. * Updated watch file. -- Jamie Wilkinson Mon, 07 Jan 2013 17:31:09 +0000 cronutils (1.2-1) unstable; urgency=low * New upstream release -- Jamie Wilkinson Mon, 21 May 2012 05:30:48 +0000 cronutils (1.1-3) unstable; urgency=low * Fix FTBFS on kfreebsd, by defining HOST_NAME_MAX. (Closes: #635212) * Put the libraries at the end of the linker call, allowing building with --as-needed linker option (Thanks, Ilya Barygin) (Closes: #637587) -- Jamie Wilkinson Wed, 17 Aug 2011 12:04:14 +1000 cronutils (1.1-2) unstable; urgency=low * Added debian/watch file. -- Jamie Wilkinson Sun, 24 Jul 2011 00:36:41 +1000 cronutils (1.1-1) unstable; urgency=low * New upstream release. -- Jamie Wilkinson Sun, 24 Jul 2011 00:29:00 +1000 cronutils (1.0-1) unstable; urgency=low * Initial release (Closes: #634124) -- Jamie Wilkinson Sun, 09 Jan 2011 14:06:35 -0800 cronutils-version-1.10/debian/compat000066400000000000000000000000021414015424400175570ustar00rootroot000000000000009 cronutils-version-1.10/debian/control000066400000000000000000000013131414015424400177620ustar00rootroot00000000000000Source: cronutils Section: admin Priority: extra Maintainer: Jamie Wilkinson Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~) Standards-Version: 3.9.6 Homepage: http://code.google.com/p/cronutils VCS-Browser: https://github.com/google/cronutils/tree/debian VCS-Git: https://github.com/google/cronutils.git -b debian Package: cronutils Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Utilities to assist running batch processing jobs A set of utilities to complement batch processing jobs, such as those run from cron, by limiting concurrent execution of jobs, setting hard limits on the runtime of a job, and recording execution statistics of a completed job. cronutils-version-1.10/debian/copyright000066400000000000000000000017671414015424400203270ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: cronutils Upstream-Contact: jaq@google.com Source: https://github.com/google/cronutils/ Files: * Copyright: 2010 Google, Inc. License: Apache-2.0 License: Apache-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. . On Debian systems, the complete text of the Apache version 2.0 license can be found in `/usr/share/common-licenses/Apache-2.0'. Files: debian/* Copyright: 2011 Jamie Wilkinson License: Apache-2.0 cronutils-version-1.10/debian/dirs000066400000000000000000000000331414015424400172410ustar00rootroot00000000000000usr/bin usr/share/man/man1 cronutils-version-1.10/debian/docs000066400000000000000000000000111414015424400172240ustar00rootroot00000000000000examples cronutils-version-1.10/debian/gbp.conf000066400000000000000000000001041414015424400177730ustar00rootroot00000000000000[DEFAULT] debian-branch = debian upstream-tag = version/%(version)s cronutils-version-1.10/debian/rules000077500000000000000000000012101414015424400174330ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed %: dh $@ override_dh_auto_install: dh_auto_install -- prefix=usr cronutils-version-1.10/debian/source/000077500000000000000000000000001414015424400176615ustar00rootroot00000000000000cronutils-version-1.10/debian/source/format000066400000000000000000000000141414015424400210670ustar00rootroot000000000000003.0 (quilt) cronutils-version-1.10/debian/watch000066400000000000000000000001131414015424400174050ustar00rootroot00000000000000version=3 https://github.com/google/cronutils/tags .*/(\d[\d\.]*)\.tar\.gz cronutils-version-1.10/examples000077500000000000000000000015351414015424400167070ustar00rootroot00000000000000#!/bin/sh ./runalarm -d -t 5 /bin/bash -c 'for i in $(seq 1 7); do echo $i; sleep 1; done; echo "exited"' ./runalarm -d -t 5 ./runstat -d -f foo /bin/bash -c 'for i in $(seq 1 7); do echo $i; sleep 1; done; echo "exited"' (./runlock -d -f ../locks/foo bash -c 'for i in $(seq 1 5); do echo $i; sleep 1; done'; echo $?) & sleep 2 ; ./runlock -d -f ../locks/foo bash -c 'for i in $(seq 1 5); do echo $i; sleep 1; done'; echo exited $? ./runlock -d -f ../locks/foo bash -c 'for i in $(seq 1 5); do echo $i; sleep 1; done' & sleep 1; cat ../locks/foo ./runlock -d bash -c 'for i in $(seq 1 5); do echo $i; sleep 1; done' ./runstat -d -f foo bash -c 'for i in $(seq 1 5); do echo $i; done; exit 5' ./runstat -d -f foo ./runalarm -d -t 5 /bin/bash -c 'for i in $(seq 1 7); do echo $i; sleep 1; done; echo exited'; cat foo ./runstat -f foo usleep 4900000; cat foo cronutils-version-1.10/regtest.sh000077500000000000000000000013521414015424400171540ustar00rootroot00000000000000#!/bin/sh SRCDIR=$(cd -P -- $(dirname -- "$0") && pwd -P) TESTDIR=$SRCDIR/tests TEMPDIR=$(mktemp -t -d cronutils.regtest-XXXXXX) trap "cd $SRCDIR; rm -rf $TEMPDIR" 0 INT QUIT ABRT PIPE TERM cd $TEMPDIR export PATH=$SRCDIR:$PATH for s in $TESTDIR/*.sh; do test=$(basename $s .sh) mkdir $TEMPDIR/$test cd $TEMPDIR/$test $s > $TEMPDIR/$test.out 2>$TEMPDIR/$test.err r=$? if [ $r -ne 0 ]; then echo $test: FAIL - exit code $r echo stdout cat $TEMPDIR/$test.out echo stderr cat $TEMPDIR/$test.err exit 1 fi diff $TESTDIR/$test.out $TEMPDIR/$test.out > $TEMPDIR/$test.diff if [ $? -ne 0 ]; then echo $test: FAIL - output match: cat $TEMPDIR/$test.diff exit 1 fi echo $test: OK cd $TEMPDIR done cronutils-version-1.10/runalarm.1000066400000000000000000000022421414015424400170420ustar00rootroot00000000000000.\" -*- nroff -*- .TH RUNALARM 1 "October 18, 2010" "Google, Inc." .SH NAME runalarm \- enforce a time limit on execution of a process .SH SYNOPSYS \fBrunalarm\fR [ \fB-h\fR ] \fBrunalarm\fR [ \fB-d\fR ] [ \fB-t \fItimeout\fR ] \fIcommand\fR [ \fIargs\fR ] .SH DESCRIPTION \fBrunalarm\fR tries to execute a command and, if the subprocess does not exit before a timer expires, tries to terminate that subprocess. Otherwise, the exit status of the command is returned. .SH USAGE .TP \fB-d\fR Debug mode; send log messages to standard error as well as to the system log. .TP \fB-t \fItimeout\fR Specifies the duration, in seconds, for \fBrunalarm\fR to allow the command to run. The default is 1d duration (86400 seconds). .TP \fB-h\fR Prints some basic help. .SH BUGS Sending SIGALRM to \fBrunalarm\fR before the timer has expired will cause the subprocess to be killed. .SH SEE ALSO \fBrunlock\fR(1), \fBrunstat\fR(1) .SH AUTHOR \fBrunalarm\fR was written by Jamie Wilkinson , based on some Python code by Craig Silverstein .SH COPYRIGHT This program is copyright (C) 2000-2010 Google, Inc. .PP It is licensed under the Apache License, Version 2.0 cronutils-version-1.10/runalarm.c000066400000000000000000000060611414015424400171270ustar00rootroot00000000000000/* Copyright 2000-2010 Google, Inc. Licensed under the Apache License, Version 2.0 (the "License"); qyou may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #define _GNU_SOURCE /* basename */ #include #include #include #include #include #include #include #include #include "subprocess.h" int timeout = 60 * 60 * 24; /* 1 day */ volatile sig_atomic_t alarm_triggered = 0; static void usage(char * prog) { fprintf(stderr, "Usage: %s [options] command [arg [arg...]]\n\n" "This program tries to run a command and, if the timeout is\n" "reached before the command exits, kills that process.\n" "Otherwise the errorcode of the command is returned.\n" "\noptions:\n" " -t timeout time in seconds to wait before process is killed\n" " -d send log messages to stderr as well as syslog.\n" " -h print this help\n", prog); } static void alarm_handler(int signum) { int old_errno; (void) signum; /* suppress unused parameter warnings */ old_errno = errno; alarm_triggered = 1; kill_process_group(); errno = old_errno; } static void set_timeout_alarm(void) { alarm(timeout); } int main(int argc, char ** argv) { int arg; char * progname; int status = -1; char * command; char ** command_args; char * endptr; struct sigaction sa, old_sa; int debug = 0; progname = argv[0]; while ((arg = getopt(argc, argv, "+t:hd")) > 0) { switch (arg) { case 'h': usage(progname); exit(EXIT_SUCCESS); break; case 't': timeout = strtol(optarg, &endptr, 10); if (*endptr || !optarg) { fprintf(stderr, "invalid timeout specified: %s\n", optarg); exit(EX_DATAERR); } break; case 'd': debug = LOG_PERROR; break; default: break; } } if (optind >= argc) { usage(progname); exit(EXIT_FAILURE); } else { command = strdup(argv[optind]); command_args = &argv[optind]; } openlog(progname, debug|LOG_ODELAY|LOG_PID|LOG_NOWAIT, LOG_CRON); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); else setlogmask(LOG_UPTO(LOG_INFO)); /* set up the alarm handler */ sigemptyset(&sa.sa_mask); sa.sa_handler = alarm_handler; sa.sa_flags = 0; sigaction(SIGALRM, &sa, &old_sa); /* exec the command */ status = run_subprocess(command, command_args, &set_timeout_alarm); alarm(0); /* shutdown the alarm */ if (alarm_triggered) { syslog(LOG_INFO, "command '%s' timed out after %d seconds", basename(command), timeout); status = 128 + SIGALRM; } closelog(); exit(status); } cronutils-version-1.10/runcron000066400000000000000000000000571414015424400165520ustar00rootroot00000000000000#!/bin/sh runalarm runlock -f $1 runstat "$@" cronutils-version-1.10/runlock.1000066400000000000000000000026621414015424400167040ustar00rootroot00000000000000.\" -*- nroff -*- .TH RUNLOCK 1 "October 18, 2010" "Google, Inc." .SH NAME runlock \- prevent concurrent execution of a process .SH SYNOPSYS \fBrunlock\fR [ \fB-h\fR ] \fBrunlock\fR [ \fB-d\fR ] [ \fB-f \fIpathname\fR ] [ \fB-t \fItimeout\fR ] \fIcommand\fR [ \fIargs\fR ] .SH DESCRIPTION \fBrunlock\fR tries to hold an exclusive lock while it executes a command. Subsequent execution of \fBrunlock\fR with the same lock, while that lock is held, will cause the new instance of \fBrunlock\fR to terminate with a failure exit code. Otherwise, the exit code of the subprocess is returned. .SH USAGE .TP \fB-d\fR Debug mode; send log messages to standard error as well as to the system log. .TP \fB-f \fIpathname\fR Specifies the pathname of the file to use as a lock file. The default is to create a lock file in /tmp/cronutils-$USER with the name of the command, and suffix ".pid". .TP \fB-t \fItimeout\fR Specifies the duration, in seconds, for \fBrunlock\fR to wait before giving up on trying to acquire the lock. The default is 5 seconds. .TP \fB-h\fR Prints some basic help. .SH BUGS Sending SIGALRM to \fBrunlock\fR before the timer has expired will cause the subprocess to be killed. .SH SEE ALSO \fBrunalarm\fR(1), \fBrunstat\fR(1) .SH AUTHOR \fBrunlock\fR was written by Jamie Wilkinson . .SH COPYRIGHT This program is copyright (C) 2010 Google, Inc. .PP It is licensed under the Apache License, Version 2.0 cronutils-version-1.10/runlock.c000066400000000000000000000106301414015424400167600ustar00rootroot00000000000000/* Copyright 2010 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #define _GNU_SOURCE /* asprintf, basename */ #include #include #include #include #include #include #include #include #include #include #include #include "subprocess.h" #include "tempdir.h" char * lock_filename = NULL; volatile sig_atomic_t timeout_expired = 0; static void usage(char * prog) { fprintf(stderr, "Usage: %s [options] command [arg [arg] ...]\n\n" "This program prevents concurrent execution of a process\n" "by holding an exclusive lock while the subprocess is running.\n" "Subsequent attempts to run a process with the same lock,\n" "while another process has the lock open, and is still\n" "executing, will exit with a failure exit code.\n", prog); fprintf(stderr, "\noptions:\n" " -d send log messages to stderr as well as syslog.\n" " -f lock_filename path to use as a lock file\n" " -t timeout time in seconds to wait to acquire the lock\n" " -h this help.\n" ); } static void alarm_handler(int signum); static void alarm_handler(int signum) { (void) signum; /* suppress unused variable warning */ timeout_expired = 1; } int main(int argc, char ** argv) { char * progname; int arg; char * command; char ** command_args; int status = 0; struct flock fl; int fd; char buf[BUFSIZ]; struct sigaction sa, old_sa; int debug = 0; int timeout = 5; char * endptr; memset(&fl, 0, sizeof(fl)); fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; progname = argv[0]; while ((arg = getopt(argc, argv, "+df:ht:")) > 0) { switch(arg) { case 'h': usage(progname); exit(EXIT_SUCCESS); break; case 'd': debug = LOG_PERROR; break; case 'f': if (asprintf(&lock_filename, "%s", optarg) == -1) { perror("asprintf"); exit(EX_OSERR); } break; case 't': timeout = strtol(optarg, &endptr, 10); if (*endptr || !optarg) { fprintf(stderr, "invalid timeout specified: %s\n", optarg); exit(EX_DATAERR); } break; default: break; } } if (optind >= argc) { usage(progname); exit(EXIT_FAILURE); } else { command = strdup(argv[optind]); command_args = &argv[optind]; } openlog(progname, debug|LOG_ODELAY|LOG_PID|LOG_NOWAIT, LOG_CRON); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); else setlogmask(LOG_UPTO(LOG_INFO)); if (lock_filename == NULL) { if (asprintf(&lock_filename, "%s/%s.pid", make_tempdir(), basename(command)) == -1) { perror("asprintf"); exit(EX_OSERR); } } syslog(LOG_DEBUG, "lock filename is %s", lock_filename); sa.sa_handler = alarm_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, &old_sa); alarm(timeout); if ((fd = open(lock_filename, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) { perror(lock_filename); exit(EX_NOINPUT); } else { if (fcntl(fd, F_SETLKW, &fl) < 0) { switch (errno) { case EINTR: if (timeout_expired) { syslog(LOG_INFO, "waited %d seconds, already locked by another process", timeout); exit(EX_CANTCREAT); } break; case EACCES: case EAGAIN: syslog(LOG_INFO, "already locked by another process"); exit(EX_CANTCREAT); break; default: perror("fcntl"); exit(EXIT_FAILURE); } } else { alarm(0); sigaction(SIGALRM, &old_sa, NULL); snprintf(buf, BUFSIZ, "%d\n", getpid()); if (write(fd, buf, strlen(buf)) == -1) { perror("write"); } fsync(fd); syslog(LOG_DEBUG, "lock granted"); status = run_subprocess(command, command_args, NULL); close(fd); } } closelog(); return status; } cronutils-version-1.10/runstat.1000066400000000000000000000022411414015424400167200ustar00rootroot00000000000000.\" -*- nroff -*- .TH RUNSTAT 1 "October 18, 2010" "Google, Inc." .SH NAME runstat \- collect statistics about execution of a process .SH SYNOPSYS \fBrunstat\fR [ \fB-h\fR ] \fBrunstat\fR [ \fB-d\fR ] [ \fB-f \fIpathname\fR ] \fIcommand\fR [ \fIargs\fR ] .SH DESCRIPTION \fBrunstat\fR tries to execute a command in a subprocess, and upon termination of the subprocess collects some statistics about that subprocess, and writes them to a file. These statistics include time of execution, exit status, and elapsed time to execute, as well as use of various OS resources. .SH USAGE .TP \fB-d\fR Debug mode; send log messages to standard error as well as to the system log. .TP \fB-f \fIpathname\fR Specifies the pathname of the file to save the statistics to. The default is to create a file in /tmp/cronutils-$USER with the name of the command, and suffix ".stat". .TP \fB-h\fR Prints some basic help. .SH SEE ALSO \fBrunalarm\fR(1), \fBrunlock\fR(1), \fBgetrusage\fR(2) .SH AUTHOR \fBrunstat\fR was written by Jamie Wilkinson . .SH COPYRIGHT This program is copyright (C) 2010 Google, Inc. .PP It is licensed under the Apache License, Version 2.0 cronutils-version-1.10/runstat.c000066400000000000000000000223461414015424400170120ustar00rootroot00000000000000/* Copyright 2010 Google, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #define _GNU_SOURCE /* dprintf, asprintf, basename */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "subprocess.h" #include "tempdir.h" static void usage(char * prog) { fprintf(stderr, "Usage: %s [options] command [arg [arg] ...]\n\n" "This program tries to execute a command in a" "subprocess, and upon termination of the subprocess" "writes some runtime statistics to a file." "These statistics include time of execution, exit" "status, and timestamp of completion.\n" "\noptions:\n" " -f path Path to save the statistics file.\n" " -C path Path to collectd socket.\n" " -d send log messages to stderr as well as syslog.\n" " -h print this help\n", prog); } enum var_kind { GAUGE, ABSOLUTE }; struct variable { struct variable * next; char * name; char * value; char * units; enum var_kind kind; }; void add_variable(struct variable ** var_list, const char * name, const enum var_kind kind, const char * units, const char * fmt, ...); void add_variable(struct variable ** var_list, const char * name, const enum var_kind kind, const char * units, const char * fmt, ...) { char buf[1024]; va_list ap; struct variable * var; var = malloc(sizeof(struct variable)); if (!var) { perror("malloc"); exit(EX_OSERR); } va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); var->name = strdup(name); var->units = units ? strdup(units) : NULL; var->value = strdup(buf); var->kind = kind; var->next = *var_list; *var_list = var; } int main(int argc, char ** argv) { char * progname; int arg; char * collectd_sockname = NULL; char * statistics_filename = NULL; char * temp_filename = NULL; char * command; char ** command_args; char * command_base; struct timeval start_wall_time, end_wall_time; struct timespec start_run_time, end_run_time; long int elapsed_sec, elapsed_nsec; int status; int temp_fd; char buf[1024]; int debug = 0; struct rusage ru; struct variable * var_list = NULL, * var; progname = argv[0]; while ((arg = getopt(argc, argv, "+C:f:hd")) > 0) { switch (arg) { case 'C': if (asprintf(&collectd_sockname, "%s", optarg) == -1) { perror("asprintf collectd_sockname"); exit(EX_OSERR); } break; case 'h': usage(progname); exit(EXIT_SUCCESS); break; case 'f': if (asprintf(&statistics_filename, "%s", optarg) == -1) { perror("asprintf"); exit(EX_OSERR); } break; case 'd': debug = LOG_PERROR; break; default: break; } } if (optind >= argc) { usage(progname); exit(EXIT_FAILURE); } else { command = strdup(argv[optind]); command_args = &argv[optind]; } openlog(progname, debug|LOG_ODELAY|LOG_PID|LOG_NOWAIT, LOG_CRON); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); else setlogmask(LOG_UPTO(LOG_INFO)); gettimeofday(&start_wall_time, NULL); clock_gettime(CLOCK_MONOTONIC, &start_run_time); status = run_subprocess(command, command_args, NULL); clock_gettime(CLOCK_MONOTONIC, &end_run_time); gettimeofday(&end_wall_time, NULL); command_base = basename(command); if (statistics_filename == NULL) { if (asprintf(&statistics_filename, "%s/%s.stat", make_tempdir(), command_base) == -1) { perror("asprintf"); exit(EX_OSERR); } } syslog(LOG_DEBUG, "statistics filename is %s", statistics_filename); if (asprintf(&temp_filename, "%s.XXXXXX", statistics_filename) == -1) { perror("asprintf"); exit(EX_OSERR); } syslog(LOG_DEBUG, "temp filename is %s", temp_filename); if ((temp_fd = mkstemp(temp_filename)) < 0) { perror("mkstemp"); exit(EX_OSERR); } /** process */ add_variable(&var_list, "exit_status", GAUGE, NULL, "%d", status); /** wall time */ /* ABSOLUTE hostname/runstat-progname/last_run-epoch_timestamp_start */ add_variable(&var_list, "start_timestamp", ABSOLUTE, "time_t", "%ld.%.6ld", start_wall_time.tv_sec, start_wall_time.tv_usec); /* ABSOLUTE hostname/runstat-progname/last_run-epoch_timestamp_end */ add_variable(&var_list, "end_timestamp", ABSOLUTE, "time_t", "%ld.%.6ld", end_wall_time.tv_sec, end_wall_time.tv_usec); /** timing */ elapsed_sec = end_run_time.tv_sec - start_run_time.tv_sec; elapsed_nsec = end_run_time.tv_nsec - start_run_time.tv_nsec; if (elapsed_nsec < 0) { elapsed_nsec += 1e9; elapsed_sec--; } /* GAUGE hostname/runstat-progname/last_run-elapsed-time */ add_variable(&var_list, "elapsed_time", GAUGE, "s", "%ld.%.9ld", elapsed_sec, elapsed_nsec); /** resource usage */ if (getrusage(RUSAGE_CHILDREN, &ru) == 0) { add_variable(&var_list, "user_time", GAUGE, "s", "%ld.%.6ld", ru.ru_utime.tv_sec, ru.ru_utime.tv_usec); add_variable(&var_list, "system_time", GAUGE, "s", "%ld.%.6ld", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec); add_variable(&var_list, "rss-max", GAUGE, "B", "%ld", ru.ru_maxrss); add_variable(&var_list, "rss-shared", GAUGE, "B", "%ld", ru.ru_ixrss); add_variable(&var_list, "rss-data_unshared", GAUGE, "B", "%ld", ru.ru_idrss); add_variable(&var_list, "rss-stack_unshared", GAUGE, "B", "%ld", ru.ru_isrss); add_variable(&var_list, "page-reclaims", GAUGE, "pages", "%ld", ru.ru_minflt); add_variable(&var_list, "page-faults", GAUGE, "pages", "%ld", ru.ru_majflt); add_variable(&var_list, "swaps", GAUGE, "swaps", "%ld", ru.ru_nswap); add_variable(&var_list, "block_ios-in", GAUGE, "block_ios", "%ld", ru.ru_inblock); add_variable(&var_list, "block_ios-out", GAUGE, "block_ios", "%ld", ru.ru_oublock); add_variable(&var_list, "messages-sent", GAUGE, "messages", "%ld", ru.ru_msgsnd); add_variable(&var_list, "messages-received", GAUGE, "messages", "%ld", ru.ru_msgrcv); add_variable(&var_list, "signals-received", GAUGE, "signals", "%ld", ru.ru_nsignals); add_variable(&var_list, "ctx_switch-voluntary", GAUGE, "context switches", "%ld", ru.ru_nvcsw); add_variable(&var_list, "ctx_switch-involuntary", GAUGE, "context switches", "%ld", ru.ru_nivcsw); } /* CSV emitter */ for (var = var_list; var != NULL; var = var->next) { snprintf(buf, sizeof(buf), "%s,%s,%s,%s\n", basename(command), var->name, var->value, var->units ? var->units : "" ); if (write(temp_fd, buf, strlen(buf)) == -1) { perror("write"); } } fsync(temp_fd); close(temp_fd); if (rename(temp_filename, statistics_filename) < 0) { perror("rename"); exit(EX_OSERR); } /* Write to collectd */ if (collectd_sockname != NULL) { char * hostname; long hostname_len; struct sockaddr_un sock; int s; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror("socket"); goto end; } sock.sun_family = AF_UNIX; strncpy(sock.sun_path, collectd_sockname, sizeof(sock.sun_path) - 1); sock.sun_path[sizeof(sock.sun_path) - 1] = '\0'; if (connect(s, (struct sockaddr*) &sock, strlen(sock.sun_path) + sizeof(sock.sun_family)) == -1) { perror("connect"); goto end; } hostname_len = sysconf(_SC_HOST_NAME_MAX); if (hostname_len <= 0) hostname_len = _POSIX_HOST_NAME_MAX; if ((hostname = malloc(hostname_len)) == NULL) { perror("malloc hostname"); exit(EX_OSERR); } if (gethostname(hostname, hostname_len) == -1) { perror("gethostname"); exit(EX_OSERR); } for (var = var_list; var != NULL; var = var->next) { char type[10] = {'\0'}; switch (var->kind) { case GAUGE: strncpy(type, "gauge", 9); break; case ABSOLUTE: strncpy(type, "counter", 9); break; default: perror("unknown var->kind"); break; } dprintf(s, "PUTVAL \"%s/runstat-%s/%s-%s\" %.0g:%s\n", hostname, command_base, type, var->name, difftime(end_wall_time.tv_sec, 0), var->value); /* This next line is a bit of a hack to clear the pipe.*/ recv(s, buf, sizeof(buf) - 1, 0); } close(s); } end: closelog(); return status; } cronutils-version-1.10/subprocess.c000066400000000000000000000100021414015424400174640ustar00rootroot00000000000000/* Copyright 2010 Google, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include #include #include #include #include #include #include #include #include "subprocess.h" int childpid = -1; /* default to a bogus pid */ volatile sig_atomic_t killed_by_us = 0; volatile sig_atomic_t fatal_error_in_progress = 0; void kill_process_group() { int pgid; killed_by_us = 1; pgid = getpgid(childpid); if (killpg(pgid, SIGTERM) < 0) { perror("killpg"); exit(EX_OSERR); } } static void termination_handler(int sig); static void termination_handler(int sig) { int old_errno; if (fatal_error_in_progress) { raise(sig); } fatal_error_in_progress = 1; if (childpid > 0) { old_errno = errno; /* we were killed (SIGTERM), so make sure child dies too */ kill_process_group(); errno = old_errno; } signal(sig, SIG_DFL); raise(sig); } void install_termination_handler(void); void install_termination_handler(void) { struct sigaction sa, old_sa; sa.sa_handler = termination_handler; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGINT); sigaddset(&sa.sa_mask, SIGHUP); sigaddset(&sa.sa_mask, SIGTERM); sigaddset(&sa.sa_mask, SIGQUIT); sa.sa_flags = 0; sigaction(SIGINT, NULL, &old_sa); if (old_sa.sa_handler != SIG_IGN) sigaction(SIGINT, &sa, NULL); sigaction(SIGHUP, NULL, &old_sa); if (old_sa.sa_handler != SIG_IGN) sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, NULL, &old_sa); if (old_sa.sa_handler != SIG_IGN) sigaction(SIGTERM, &sa, NULL); } int run_subprocess(char * command, char ** args, void (*pre_wait_function)(void)) { int pid; int status; childpid = fork(); if (childpid == 0) { /* try to detach from parent's process group */ if (setsid() == -1) { syslog(LOG_ERR, "Unable to detach child. Aborting"); return -1; } if (execvp(command, args)) { perror("execvp"); exit(EX_NOINPUT); } else { /* Control almost certainly will not get to this point, ever. If * the call to execvp returned, instead of switching to a new memory * image, there was a problem. This exit will be collected by the * parent's call to waitpid() below. */ exit(EX_UNAVAILABLE); } } else if (childpid < 0) { perror("fork"); exit(EX_OSERR); } else { /* Make sure the child dies if we get killed. */ /* Only the parent should do this, of course! */ install_termination_handler(); if (pre_wait_function != NULL) { pre_wait_function(); } /* blocking wait on the child */ while ((pid = waitpid(childpid, &status, 0)) < 0) { if (errno == EINTR) { if (killed_by_us) { break; } /* else restart the loop */ } else { perror("waitpid"); } } alarm(0); if (pid > 0) { if (pid != childpid) { syslog(LOG_ERR, "childpid %d not returned by waitpid! instead %d", childpid, pid); kill_process_group(); exit(EX_OSERR); } /* exited normally? */ if (WIFEXITED(status)) { /* decode and return exit sttus */ status = WEXITSTATUS(status); syslog(LOG_DEBUG, "child exited with status %d", status); } else { /* This formula is a Unix shell convention */ status = 128 + WTERMSIG(status); syslog(LOG_DEBUG, "child exited via signal %d", WTERMSIG(status)); } } childpid = -1; } return status; } cronutils-version-1.10/subprocess.h000066400000000000000000000003301414015424400174740ustar00rootroot00000000000000#ifndef __CRONUTILS_SUBPROCESS_H #define __CRONUTILS_SUBPROCESS_H void kill_process_group(); int run_subprocess(char * command, char ** args, void (*pre_wait_function)(void)); #endif /* __CRONUTILS_SUBPROCESS_H */ cronutils-version-1.10/tempdir.c000066400000000000000000000036211414015424400167510ustar00rootroot00000000000000/* Copyright 2010 Google, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #define _GNU_SOURCE /* asprintf */ #include #include #include #include #include #include #include #include #include #include #include #include "tempdir.h" const char * template = "/tmp/cronutils-"; char * dirname = NULL; char * make_tempdir() { uid_t uid; struct passwd * pw; struct stat st; uid = geteuid(); if ((pw = getpwuid(uid)) == NULL) { perror("getpwuid"); exit(EX_OSERR); } if (asprintf(&dirname, "%s%s", template, pw->pw_name) == -1) { perror("asprintf"); exit(EX_OSERR); } syslog(LOG_DEBUG, "temp dir is %s\n", dirname); if (mkdir(dirname, S_IRWXU) < 0) { if (errno == EEXIST) { if (stat(dirname, &st) != 0) { perror("stat"); exit(EX_OSERR); } if (!S_ISDIR(st.st_mode)) { syslog(LOG_ERR, "%s is not a directory\n", dirname); exit(EX_IOERR); } if (st.st_uid != uid) { syslog(LOG_ERR, "%s is not owned by %s\n", dirname, pw->pw_name); exit(EXIT_FAILURE); } if (!(st.st_mode & S_IRWXU)) { syslog(LOG_ERR, "%s has insecure permissions %u\n", dirname, st.st_mode); exit(EXIT_FAILURE); } } else { perror("mkdir"); exit(EX_OSERR); } } return dirname; } cronutils-version-1.10/tempdir.h000066400000000000000000000012571414015424400167610ustar00rootroot00000000000000/* Copyright 2010 Google, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef __CRONUTILS_TEMPDIR_H__ #define __CRONUTILS_TEMPDIR_H__ char * make_tempdir(); #endif /* __CRONUTILS_TEMPDIR_H__ */ cronutils-version-1.10/tests/000077500000000000000000000000001414015424400163015ustar00rootroot00000000000000cronutils-version-1.10/tests/1.out000066400000000000000000000000121414015424400171630ustar00rootroot000000000000001 2 3 4 5 cronutils-version-1.10/tests/1.sh000077500000000000000000000003561414015424400170040ustar00rootroot00000000000000#!/bin/sh runalarm -d -t 5 /bin/bash -c 'for i in $(seq 1 7); do echo $i; sleep 1; done; echo "exited"' r=$? # Should be nonzero exit when killed, sigalarm if [ $r -eq 142 ]; then exit 0 elif [ $r -eq 0 ]; then exit 1 else exit $r fi cronutils-version-1.10/tests/2.out000066400000000000000000000000121414015424400171640ustar00rootroot000000000000001 2 3 4 5 cronutils-version-1.10/tests/2.sh000077500000000000000000000003551414015424400170040ustar00rootroot00000000000000#!/bin/sh runalarm -d -t 5 runstat -d -f foo /bin/bash -c 'for i in $(seq 1 7); do echo $i; sleep 1; done; echo "exited"' r=$? if [ $r -ne 142 ]; then exit 1 fi # runstat never got chance to write stats if [ -e foo ]; then exit 1 fi cronutils-version-1.10/tests/3.out000066400000000000000000000000261414015424400171720ustar00rootroot000000000000001 2 3 4 5 0 1 2 3 4 5 cronutils-version-1.10/tests/3.sh000077500000000000000000000003561414015424400170060ustar00rootroot00000000000000#!/bin/sh ( runlock -d -f lock bash -c 'for i in $(seq 1 5); do echo $i; sleep 1; done' r=$? echo $r if [ $r -ne 0 ]; then exit 1 fi ) & sleep 2 runlock -d -f lock bash -c 'for i in $(seq 1 5); do echo $i; sleep 1; done' cronutils-version-1.10/tests/4.out000066400000000000000000000000121414015424400171660ustar00rootroot000000000000001 2 3 4 5 cronutils-version-1.10/tests/4.sh000077500000000000000000000002711414015424400170030ustar00rootroot00000000000000#!/bin/sh runstat -d -f foo bash -c 'for i in $(seq 1 5); do echo $i; done; exit 5' r=$? if [ $r -ne 5 ]; then exit 1 fi grep -q 'bash,exit_status,5' foo && exit 0 cat foo exit 1 cronutils-version-1.10/tests/5.out000066400000000000000000000000121414015424400171670ustar00rootroot000000000000001 2 3 4 5 cronutils-version-1.10/tests/5.sh000077500000000000000000000003431414015424400170040ustar00rootroot00000000000000#!/bin/sh runstat -d -f foo runalarm -d -t 5 /bin/bash -c 'for i in $(seq 1 7); do echo $i; sleep 1; done; echo exited' r=$? if [ $r -ne 142 ]; then exit 1 fi grep -q 'runalarm,exit_status,142' foo && exit 0 cat foo exit 1 cronutils-version-1.10/version000066400000000000000000000000041414015424400165410ustar00rootroot000000000000001.9