Compare commits
No commits in common. "pristine-tar" and "master" have entirely different histories.
pristine-t
...
master
8
AUTHORS
Normal file
8
AUTHORS
Normal file
@ -0,0 +1,8 @@
|
||||
Original vixie-cron was written by Paul Vixie.
|
||||
|
||||
Significant contributors:
|
||||
Marcela Mašláňová <mmaslano@redhat.com>
|
||||
Colin Dean <colin@colin-dean.org>
|
||||
Tomáš Mráz <tmraz@fedoraproject.org>
|
||||
Marco Migliori <sgerwk@aol.com>
|
||||
Sami Kerola <kerolasa@iki.fi>
|
417
COPYING
Normal file
417
COPYING
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1988, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software written by Ken Arnold and
|
||||
* published in UNIX Review, Vol. 6, No. 8.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Paul Vixie.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)bitstring.h 8.1 (Berkeley) 7/19/93
|
||||
*/
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
339
COPYING.anacron
Normal file
339
COPYING.anacron
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
510
COPYING.obstack
Normal file
510
COPYING.obstack
Normal file
@ -0,0 +1,510 @@
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations
|
||||
below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it
|
||||
becomes a de-facto standard. To achieve this, non-free programs must
|
||||
be allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control
|
||||
compilation and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at least
|
||||
three years, to give the same user the materials specified in
|
||||
Subsection 6a, above, for a charge no more than the cost of
|
||||
performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply, and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License
|
||||
may add an explicit geographical distribution limitation excluding those
|
||||
countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms
|
||||
of the ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library.
|
||||
It is safest to attach them to the start of each source file to most
|
||||
effectively convey the exclusion of warranty; and each file should
|
||||
have at least the "copyright" line and a pointer to where the full
|
||||
notice is found.
|
||||
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
your school, if any, to sign a "copyright disclaimer" for the library,
|
||||
if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James
|
||||
Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
17
INSTALL
Normal file
17
INSTALL
Normal file
@ -0,0 +1,17 @@
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Run the usual autotools combination of:
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
If no "configure" script is present, generate it by:
|
||||
./autogen.sh
|
||||
|
||||
The executable files will be installed in /usr/local/* by default.
|
||||
|
||||
Configure Options
|
||||
=================
|
||||
Please see the ./configure --help output for available build-time
|
||||
options.
|
36
Makefile.am
Normal file
36
Makefile.am
Normal file
@ -0,0 +1,36 @@
|
||||
AM_CFLAGS = -I$(top_srcdir)
|
||||
|
||||
BUILT_SOURCES =
|
||||
CLEANFILES =
|
||||
EXTRA_DIST =
|
||||
bin_PROGRAMS =
|
||||
common_nodist =
|
||||
sbin_PROGRAMS =
|
||||
|
||||
dist_noinst_HEADERS = \
|
||||
cronie_common.h
|
||||
|
||||
EXTRA_DIST += \
|
||||
README.anacron \
|
||||
COPYING.anacron \
|
||||
COPYING.obstack \
|
||||
obstack/obstack.h \
|
||||
cronie.init \
|
||||
crond.sysconfig \
|
||||
contrib/anacrontab \
|
||||
contrib/0anacron \
|
||||
contrib/0hourly \
|
||||
contrib/dailyjobs \
|
||||
contrib/cronie.systemd \
|
||||
anacron/ChangeLog.anacron
|
||||
|
||||
if PAM
|
||||
pamdir = $(sysconfdir)/pam.d
|
||||
dist_pam_DATA = pam/crond
|
||||
else
|
||||
EXTRA_DIST += pam/crond
|
||||
endif
|
||||
|
||||
include anacron/Makemodule.am
|
||||
include man/Makemodule.am
|
||||
include src/Makemodule.am
|
1388
Makefile.in
Normal file
1388
Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
79
NEWS
Normal file
79
NEWS
Normal file
@ -0,0 +1,79 @@
|
||||
cronie NEWS -- history of user-visible changes.
|
||||
|
||||
Release 1.6.1
|
||||
|
||||
* crond: Fix regression of handling ranges (x-y) in crontab
|
||||
|
||||
Release 1.6.0
|
||||
|
||||
* crond: Add switch -f as an alias for -n
|
||||
* crond: Add random within range '~' operator
|
||||
* crond: Use the configure runstatedir directory for pid file
|
||||
* crond: Increase the maximum number of crontab entries to 10000
|
||||
|
||||
Release 1.5.7
|
||||
|
||||
* anacron: Fix problem of anacron not being started on some desktops
|
||||
* crontab: switch off colors if NO_COLOR is set
|
||||
|
||||
Release 1.5.6
|
||||
|
||||
* crontab: crontab without arguments now works if stdin is not a TTY
|
||||
* crond: Fix various issues on loading the crontab databases on startup
|
||||
* anacron: Expand MAILTO and MAILFROM environment variables
|
||||
* crontab: New option to test crontab file syntax without installing it
|
||||
|
||||
Release 1.5.5
|
||||
|
||||
* Explicitly validate upper end of range and step to disallow entries
|
||||
such as: 1-234/5678 * * * * ....
|
||||
* crond: Report missing newline before EOF in syslog so the line is not
|
||||
completely silently ignored.
|
||||
* crontab -l colors comment lines in a different color.
|
||||
* crond: Revert "Avoid creating pid files when crond doesn't fork".
|
||||
* anacron is built by default.
|
||||
* Use non-recursive build.
|
||||
* cronnext: Allow to optionally select jobs by substring.
|
||||
|
||||
Release 1.5.4
|
||||
|
||||
* crond: Fix regression from previous release. Only first job from a crontab
|
||||
was being run.
|
||||
|
||||
Release 1.5.3
|
||||
|
||||
* Fix CVE-2019-9704 and CVE-2019-9705 to avoid local DoS of the crond.
|
||||
* crontab: Make crontab without arguments fail.
|
||||
* crond: In PAM configuration include system-auth instead of password-auth.
|
||||
* crond: In the systemd service file restart crond if it fails.
|
||||
* crond: Use the role from the crond context for system job contexts.
|
||||
* Multiple small cleanups and fixes.
|
||||
|
||||
Release 1.5.2
|
||||
|
||||
* cronnext: New useful utility to find out time of the next job run.
|
||||
* crond: Avoid creating PID files when crond doesn't fork.
|
||||
* crontab: Do not try to replace the crontab with a directory.
|
||||
* crond: Log startup even when started in non-forking mode.
|
||||
* Multiple small cleanups and fixes.
|
||||
|
||||
Release 1.5.1
|
||||
|
||||
* crontab: Use temporary file name that is ignored by crond.
|
||||
* crond: Inherit PATH from the crond environment if -P option is used.
|
||||
* crond: Remove hardcoded "system_u" SELinux user, use the SELinux user
|
||||
of the running crond.
|
||||
* anacron: Small cleanups and fixes.
|
||||
* crond: Fix longstanding race condition on repeated crontab modification.
|
||||
|
||||
Release 1.5.0
|
||||
|
||||
* First release with NEWS. :)
|
||||
* crond: Job environment variables are set also when executing sendmail.
|
||||
* crond: Adding duplicate orphans on reload is now prevented.
|
||||
* crond: The regular crond shutdown is now logged.
|
||||
* crontab: PAM is not called in crontab command if the caller's uid is 0.
|
||||
* crond: PAM is not called from crond for system cron jobs
|
||||
(/etc/crontab, /etc/cron.d) which are run for uid 0.
|
||||
* crond: The existence of an user is checked at time when job is run
|
||||
and not when the crontab is parsed on database reload.
|
13
README
Normal file
13
README
Normal file
@ -0,0 +1,13 @@
|
||||
Cronie contains the standard UNIX daemon crond that runs specified programs at
|
||||
scheduled times and related tools. The source is based on the original vixie-cron
|
||||
and has security and configuration enhancements like the ability to use pam and
|
||||
SELinux.
|
||||
|
||||
And why cronie? See http://www.urbandictionary.com/define.php?term=cronie
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
Mailing list: `cronie-devel AT lists.fedorahosted DOT org`
|
||||
|
||||
Bug reports and pull requests can be filled at the Github site.
|
142
README.anacron
Normal file
142
README.anacron
Normal file
@ -0,0 +1,142 @@
|
||||
|
||||
What is Anacron ?
|
||||
-----------------
|
||||
|
||||
Anacron is a periodic command scheduler. It executes commands at
|
||||
intervals specified in days. Unlike cron, it does not assume that the
|
||||
system is running continuously. It can therefore be used to control
|
||||
the execution of daily, weekly and monthly jobs (or anything with a
|
||||
period of n days), on systems that don't run 24 hours a day. When
|
||||
installed and configured properly, Anacron will make sure that the
|
||||
commands are run at the specified intervals as closely as
|
||||
machine-uptime permits.
|
||||
|
||||
Every time Anacron is run, it reads a configuration file that
|
||||
specifies the jobs Anacron controls, and their periods in days. If a
|
||||
job wasn't executed in the last n days, where n is the period of that
|
||||
job, Anacron executes it. Anacron then records the date in a special
|
||||
timestamp file that it keeps for each job, so it can know when to run
|
||||
it again. When all the executed commands terminate, Anacron exits.
|
||||
|
||||
It is recommended to run Anacron from the system boot-scripts.
|
||||
This way the jobs "whose time has come" will be run shortly after the
|
||||
machine boots. A delay can be specified for each job so that the
|
||||
machine isn't overloaded at boot time.
|
||||
|
||||
In addition to running Anacron from the boot-scripts, it is also
|
||||
recommended to schedule it as a daily cron-job (usually at an early
|
||||
morning hour), so that if the machine is kept running for a night,
|
||||
jobs for the next day will still be executed.
|
||||
|
||||
|
||||
Why this may be useful ?
|
||||
------------------------
|
||||
|
||||
Most Unix-like systems have daily, weekly and monthly scripts that
|
||||
take care of various "housekeeping chores" such as log-rotation,
|
||||
updating the "locate" and "man" databases, etc. Daily scripts are
|
||||
usually scheduled as cron-jobs to execute around 1-7 AM. Weekly
|
||||
scripts are scheduled to run on Sundays. On machines that are turned
|
||||
off for the night or for the weekend, these scripts rarely get run.
|
||||
|
||||
Anacron solves this problem. These jobs can simply be scheduled as
|
||||
Anacron-jobs with periods of 1, 7 and a special target called @monthly.
|
||||
|
||||
|
||||
What Anacron is not ?
|
||||
---------------------
|
||||
|
||||
Anacron is not an attempt to make cron redundant. It cannot
|
||||
currently be used to schedule commands at intervals smaller than days.
|
||||
It also does not guarantee that the commands will be executed at any
|
||||
specific day or hour.
|
||||
|
||||
It isn't a full-time daemon. It has to be executed from boot
|
||||
scripts, from cron-jobs, or explicitly.
|
||||
|
||||
|
||||
For more details, see the anacron(8) manpage.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- A Linux system. (maybe other *NIX systems)
|
||||
- A functioning syslog daemon.
|
||||
- A functioning /usr/lib/sendmail command. (all MTAs should have
|
||||
that).
|
||||
|
||||
|
||||
Compilation and Installation
|
||||
----------------------------
|
||||
|
||||
- Untar the source package.
|
||||
|
||||
- Check the Makefile. Edit as required.
|
||||
|
||||
- Check the top of "global.h". You may want to change the syslog
|
||||
facility and priorities, and the path to your MTA's sendmail
|
||||
compatible command (/usr/lib/sendmail).
|
||||
|
||||
- cd to the directory.
|
||||
|
||||
- Type "make".
|
||||
You can safely ignore warnings of the form: "*.d: No such file or
|
||||
directory"
|
||||
|
||||
- Become root. Type "make install".
|
||||
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
1. Locate your system's daily, weekly and monthly cron-jobs.
|
||||
See your cron documentation for more details.
|
||||
|
||||
2. Decide which of these jobs should be controlled by Anacron.
|
||||
Remember that Anacron does not guarantee execution at any specific
|
||||
day of the month, day of the week, or time of day. Jobs for which
|
||||
the timing is critical should probably not be controlled by
|
||||
Anacron.
|
||||
|
||||
3. Comment these jobs out of their crontab files. (You may have to
|
||||
use the "crontab" command for this. See the cron documentation.)
|
||||
|
||||
4. Put them in /etc/anacrontab. Note that the format is not the same
|
||||
as the crontab entries. See the anacrontab(5) manpage. Here's an
|
||||
example from a typical Debian system:
|
||||
|
||||
-----Cut
|
||||
# /etc/anacrontab example
|
||||
SHELL=/bin/sh
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
# format: period delay job-identifier command
|
||||
1 5 cron.daily run-parts /etc/cron.daily
|
||||
7 10 cron.weekly run-parts /etc/cron.weekly
|
||||
@monthly 15 cron.monthly run-parts /etc/cron.monthly
|
||||
-----Cut
|
||||
|
||||
5. Put the command "anacron -s" somewhere in your boot-scripts.
|
||||
Make sure that syslogd is started before this command.
|
||||
|
||||
6. Schedule the command "anacron -s" as a daily cron-job (preferably
|
||||
at some early morning hour). This will make sure that jobs are run
|
||||
when the systems is left running for a night.
|
||||
|
||||
That's it.
|
||||
|
||||
It is a good idea to check what your daily, weekly and monthly scripts
|
||||
actually do, and disable any parts that may be irrelevant for your
|
||||
system.
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
Anacron was originally conceived and implemented by Christian Schwarz
|
||||
<schwarz@monet.m.isar.de>.
|
||||
|
||||
The current implementation is a complete rewrite by Itai Tzur
|
||||
<itzur@actcom.co.il>.
|
||||
|
||||
Current code base maintained by Sean 'Shaleh' Perry <shaleh@(debian.org|valinux.com)>.
|
1137
aclocal.m4
vendored
Normal file
1137
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
anacron-paths.h
Normal file
7
anacron-paths.h
Normal file
@ -0,0 +1,7 @@
|
||||
/* This file has been automatically generated. Do not edit. */
|
||||
|
||||
#ifndef _ANACRON_PATHS_H_
|
||||
#define _ANACRON_PATHS_H_
|
||||
#define ANACRON_SPOOL_DIR "/usr/local/var/spool/anacron"
|
||||
#define ANACRONTAB "/usr/local/etc/anacrontab"
|
||||
#endif /* _ANACRON_PATHS_H_ */
|
39
anacron/ChangeLog.anacron
Normal file
39
anacron/ChangeLog.anacron
Normal file
@ -0,0 +1,39 @@
|
||||
Changes in Anacron 2.3.1
|
||||
------------------------
|
||||
* documentation no longer suggests adding local directories to the PATH
|
||||
|
||||
|
||||
Changes in Anacron 2.3
|
||||
----------------------
|
||||
* anacron can now read an arbitrary anacrontab file, use the -t option
|
||||
|
||||
|
||||
Changes in Anacron 2.1/2.2
|
||||
--------------------------
|
||||
* Sean 'Shaleh' Perry <shaleh@(debian.org|valinux.com)> is now maintainer
|
||||
* if timestamp is from the future, re-run job
|
||||
* ansi cleanup / code cleaning
|
||||
|
||||
|
||||
Changes in Anacron 2.0.1
|
||||
------------------------
|
||||
* Minor cosmetic changes to log messages.
|
||||
* Jobs are now started with "/" as their working directory. This is
|
||||
more compatible with older Anacron versions, avoids annoying errors on
|
||||
some systems, and generally seems to make more sense.
|
||||
|
||||
|
||||
Summary of major changes in Anacron 2.0
|
||||
---------------------------------------
|
||||
* Complete rewrite in C. Should be backwards compatible with existing
|
||||
Anacron installations.
|
||||
* First release as a "generic" Linux package (was a Debian package).
|
||||
* No longer needs special lock-files. Locking is done on the timestamp
|
||||
files.
|
||||
* Sends log messages to syslogd. There's no log file now.
|
||||
* Output of jobs, if any, is mailed to the user.
|
||||
* Added command line options: -s -f -n -d -q -u -V -h. See the manpage.
|
||||
* Specific jobs can now be selected on the command line.
|
||||
* Added SIGUSR1 handling, to cleanly stop execution.
|
||||
* Jobs will now be started with their current directory set to the home
|
||||
of the user running Anacron (usually root).
|
42
anacron/Makemodule.am
Normal file
42
anacron/Makemodule.am
Normal file
@ -0,0 +1,42 @@
|
||||
# Makefile.am - two binaries crond and crontab
|
||||
if ANACRON
|
||||
sbin_PROGRAMS += anacron/anacron
|
||||
anacron_anacron_SOURCES = \
|
||||
anacron-paths.h \
|
||||
anacron/global.h \
|
||||
anacron/gregor.c \
|
||||
anacron/gregor.h \
|
||||
anacron/lock.c \
|
||||
anacron/log.c \
|
||||
anacron/main.c \
|
||||
anacron/matchrx.c \
|
||||
anacron/matchrx.h \
|
||||
anacron/readtab.c \
|
||||
anacron/runjob.c \
|
||||
cronie_common.c
|
||||
common_nodist += anacron-paths.h
|
||||
nodist_anacron_anacron_SOURCES = $(common_nodist)
|
||||
BUILT_SOURCES += $(common_nodist)
|
||||
|
||||
if NEED_OBSTACK
|
||||
anacron_anacron_SOURCES += obstack/obstack.c
|
||||
endif
|
||||
|
||||
anacron_anacron_LDADD = $(LIBSELINUX) $(LIBPAM) $(LIBAUDIT)
|
||||
|
||||
# This header contains all the paths.
|
||||
# If they are configurable, they are declared in configure script.
|
||||
# Depends on this Makefile, because it uses make variables.
|
||||
CLEANFILES += anacron-paths.h
|
||||
anacron-paths.h: Makefile
|
||||
@echo 'creating $@'
|
||||
@sed >$@ 's/ *\\$$//' <<\END #\
|
||||
/* This file has been automatically generated. Do not edit. */ \
|
||||
\
|
||||
#ifndef _ANACRON_PATHS_H_ \
|
||||
#define _ANACRON_PATHS_H_ \
|
||||
#define ANACRON_SPOOL_DIR "$(ANACRON_SPOOL_DIR)" \
|
||||
#define ANACRONTAB "$(ANACRONTAB)" \
|
||||
#endif /* _ANACRON_PATHS_H_ */ \
|
||||
END
|
||||
endif
|
163
anacron/global.h
Normal file
163
anacron/global.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
#ifndef _ANACRON_GLOBAL_H
|
||||
#define _ANACRON_GLOBAL_H
|
||||
|
||||
/* Syslog facility and priorities messages will be logged to (see syslog(3)).
|
||||
* If you change these, please update the man page. */
|
||||
#define SYSLOG_FACILITY LOG_CRON
|
||||
#define EXPLAIN_LEVEL LOG_NOTICE /* informational messages */
|
||||
#define COMPLAIN_LEVEL LOG_ERR /* error messages */
|
||||
#define DEBUG_LEVEL LOG_DEBUG /* only used when DEBUG is defined */
|
||||
|
||||
/* Mail interface. (All MTAs should supply this command) */
|
||||
#define SENDMAIL "/usr/sbin/sendmail"
|
||||
|
||||
/* End of user-configurable section */
|
||||
|
||||
|
||||
#define FAILURE_EXIT 1
|
||||
#define MAX_MSG 150
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include "anacron-paths.h"
|
||||
#include "cronie_common.h"
|
||||
|
||||
/* Some declarations */
|
||||
|
||||
struct env_rec1 {
|
||||
char *assign;
|
||||
|
||||
struct env_rec1 *next;
|
||||
};
|
||||
typedef struct env_rec1 env_rec;
|
||||
|
||||
struct job_rec1 {
|
||||
int period;
|
||||
int named_period;
|
||||
int delay;
|
||||
char *ident;
|
||||
char *command;
|
||||
char *mailto;
|
||||
|
||||
int tab_line;
|
||||
int arg_num;
|
||||
int timestamp_fd;
|
||||
int input_fd;
|
||||
int output_fd;
|
||||
off_t mail_header_size;
|
||||
pid_t job_pid;
|
||||
pid_t mailer_pid;
|
||||
int drop_job;
|
||||
|
||||
struct job_rec1 *next;
|
||||
env_rec *prev_env_rec;
|
||||
};
|
||||
typedef struct job_rec1 job_rec;
|
||||
|
||||
/* Global variables */
|
||||
|
||||
extern pid_t primary_pid;
|
||||
extern char *program_name;
|
||||
extern char *anacrontab;
|
||||
extern char *spooldir;
|
||||
extern int old_umask;
|
||||
extern sigset_t old_sigmask;
|
||||
extern int serialize,force,update_only,now,no_daemon,quiet,testing_only;
|
||||
extern int day_now;
|
||||
extern int year,month,day_of_month;
|
||||
extern int in_background;
|
||||
|
||||
extern job_rec *first_job_rec;
|
||||
extern env_rec *first_env_rec;
|
||||
|
||||
extern char **job_args;
|
||||
extern int job_nargs;
|
||||
|
||||
extern int njobs;
|
||||
extern job_rec **job_array;
|
||||
|
||||
extern int running_jobs,running_mailers;
|
||||
|
||||
extern int complaints;
|
||||
|
||||
extern time_t start_sec;
|
||||
|
||||
/* time ranges for START_HOURS_RANGE */
|
||||
extern int range_start;
|
||||
extern int range_stop;
|
||||
|
||||
/* preferred hour for jobs */
|
||||
extern int preferred_hour;
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/* main.c */
|
||||
int xopen(int fd, const char *file_name, int flags);
|
||||
void xclose(int fd);
|
||||
pid_t xfork(void);
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PRINTF_FORMAT(n, m) \
|
||||
__attribute__ ((format (printf, n, m)))
|
||||
#else
|
||||
#define PRINTF_FORMAT(n, m)
|
||||
#endif
|
||||
|
||||
/* log.c */
|
||||
void explain(const char *fmt, ...)PRINTF_FORMAT(1,2);
|
||||
void explain_e(const char *fmt, ...)PRINTF_FORMAT(1,2);
|
||||
void complain(const char *fmt, ...)PRINTF_FORMAT(1,2);
|
||||
void complain_e(const char *fmt, ...)PRINTF_FORMAT(1,2);
|
||||
void die(const char *fmt, ...)PRINTF_FORMAT(1,2) ATTRIBUTE_NORETURN;
|
||||
void die_e(const char *fmt, ...)PRINTF_FORMAT(1,2) ATTRIBUTE_NORETURN;
|
||||
void xdebug(const char *fmt, ...)PRINTF_FORMAT(1,2);
|
||||
void xdebug_e(const char *fmt, ...)PRINTF_FORMAT(1,2);
|
||||
void xcloselog(void);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define Debug(args) xdebug args
|
||||
#define Debug_e(args) xdebug_e args
|
||||
#else /* not DEBUG */
|
||||
#define Debug(args) (void)(0)
|
||||
#define Debug_e(args) (void)(0)
|
||||
#endif /* not DEBUG */
|
||||
|
||||
/* readtab.c */
|
||||
void read_tab(int cwd);
|
||||
void arrange_jobs(void);
|
||||
|
||||
/* lock.c */
|
||||
int consider_job(job_rec *jr);
|
||||
void unlock(job_rec *jr);
|
||||
void update_timestamp(job_rec *jr);
|
||||
void fake_job(job_rec *jr);
|
||||
|
||||
/* runjob.c */
|
||||
void tend_children();
|
||||
void launch_job(job_rec *jr);
|
||||
|
||||
#endif
|
181
anacron/gregor.c
Normal file
181
anacron/gregor.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include "gregor.h"
|
||||
|
||||
static const int
|
||||
days_in_month[] = {
|
||||
31, /* Jan */
|
||||
28, /* Feb (non-leap) */
|
||||
31, /* Mar */
|
||||
30, /* Apr */
|
||||
31, /* May */
|
||||
30, /* Jun */
|
||||
31, /* Jul */
|
||||
31, /* Aug */
|
||||
30, /* Sep */
|
||||
31, /* Oct */
|
||||
30, /* Nov */
|
||||
31 /* Dec */
|
||||
};
|
||||
|
||||
static int leap(int year);
|
||||
|
||||
int
|
||||
day_num(int year, int month, int day)
|
||||
/* Return the "day number" of the date year-month-day according to the
|
||||
* "proleptic Gregorian calendar".
|
||||
* If the given date is invalid, return -1.
|
||||
*
|
||||
* Here, "day number" is defined as the number of days since December 31,
|
||||
* 1 B.C. (Gregorian). (January 1, 1 A.D. is day number 1 etc...)
|
||||
*
|
||||
* The Gregorian calendar was instituted by Pope Gregory XIII in 1582,
|
||||
* and has gradually spread to become the international standard calendar.
|
||||
* The proleptic Gregorian calendar is formed by projecting the date system
|
||||
* of the Gregorian calendar to dates before its adoption.
|
||||
*
|
||||
* For more details, see:
|
||||
* http://astro.nmsu.edu/~lhuber/leaphist.html
|
||||
* http://www.magnet.ch/serendipity/hermetic/cal_stud/cal_art.htm
|
||||
* and your local library.
|
||||
*/
|
||||
{
|
||||
int dn;
|
||||
int i;
|
||||
int isleap; /* save three calls to leap() */
|
||||
|
||||
/* Some validity checks */
|
||||
|
||||
/* we don't deal with B.C. years here */
|
||||
if (year < 1) return - 1;
|
||||
/* conservative overflow estimate */
|
||||
if (year > (INT_MAX / 366)) return - 1;
|
||||
if (month > 12 || month < 1) return - 1;
|
||||
if (day < 1) return - 1;
|
||||
|
||||
isleap = leap(year);
|
||||
|
||||
if (month != 2) {
|
||||
if(day > days_in_month[month - 1]) return - 1;
|
||||
}
|
||||
else if ((isleap && day > 29) || (!isleap && day > 28))
|
||||
return - 1;
|
||||
|
||||
/* First calculate the day number of December 31 last year */
|
||||
|
||||
/* save us from doing (year - 1) over and over */
|
||||
i = year - 1;
|
||||
/* 365 days in a "regular" year + number of leap days */
|
||||
dn = (i * 365) + ((i / 4) - (i / 100) + (i / 400));
|
||||
|
||||
/* Now, day number of the last day of the previous month */
|
||||
|
||||
for (i = month - 1; i > 0; --i)
|
||||
dn += days_in_month[i - 1];
|
||||
/* Add 29 February ? */
|
||||
if (month > 2 && isleap) ++dn;
|
||||
|
||||
/* How many days into month are we */
|
||||
|
||||
dn += day;
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
static int
|
||||
leap(int year)
|
||||
/* Is this a leap year ? */
|
||||
{
|
||||
/* every year exactly divisible by 4 is "leap" */
|
||||
/* unless it is exactly divisible by 100 */
|
||||
/* but not by 400 */
|
||||
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
|
||||
}
|
||||
|
||||
int
|
||||
days_last_month (void)
|
||||
/* How many days did last month have? */
|
||||
{
|
||||
struct tm time_record;
|
||||
time_t current_time;
|
||||
time (¤t_time);
|
||||
localtime_r (¤t_time, &time_record);
|
||||
|
||||
switch (time_record.tm_mon) {
|
||||
case 0: return days_in_month[11];
|
||||
case 2: return days_in_month[1] + (leap (time_record.tm_year + 1900) ? 1 : 0);
|
||||
default: return days_in_month[time_record.tm_mon - 1];
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
days_this_month (void)
|
||||
/* How many days does this month have? */
|
||||
{
|
||||
struct tm time_record;
|
||||
time_t current_time;
|
||||
time (¤t_time);
|
||||
localtime_r (¤t_time, &time_record);
|
||||
|
||||
switch (time_record.tm_mon) {
|
||||
case 1: return days_in_month[1] + (leap (time_record.tm_year + 1900) ? 1 : 0);
|
||||
default: return days_in_month[time_record.tm_mon];
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
days_last_year (void)
|
||||
/* How many days this last year have? */
|
||||
{
|
||||
struct tm time_record;
|
||||
time_t current_time;
|
||||
time (¤t_time);
|
||||
localtime_r (¤t_time, &time_record);
|
||||
|
||||
if (leap(time_record.tm_year - 1 + 1900)) {
|
||||
return 366;
|
||||
}
|
||||
|
||||
return 365;
|
||||
}
|
||||
|
||||
int
|
||||
days_this_year (void)
|
||||
/* How many days does this year have */
|
||||
{
|
||||
struct tm time_record;
|
||||
time_t current_time;
|
||||
time (¤t_time);
|
||||
localtime_r (¤t_time, &time_record);
|
||||
|
||||
if (leap(time_record.tm_year + 1900)) {
|
||||
return 366;
|
||||
}
|
||||
|
||||
return 365;
|
||||
}
|
30
anacron/gregor.h
Normal file
30
anacron/gregor.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
int day_num(int year, int month, int day);
|
||||
int days_last_month (void);
|
||||
int days_this_month (void);
|
||||
int days_last_year (void);
|
||||
int days_this_year (void);
|
217
anacron/lock.c
Normal file
217
anacron/lock.c
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyirght (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
/* Lock and timestamp management
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include "global.h"
|
||||
#include "gregor.h"
|
||||
|
||||
static void
|
||||
open_tsfile(job_rec *jr)
|
||||
/* Open the timestamp file for job jr */
|
||||
{
|
||||
jr->timestamp_fd = open(jr->ident, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (jr->timestamp_fd == -1)
|
||||
die_e("Can't open timestamp file for job %s", jr->ident);
|
||||
fcntl(jr->timestamp_fd, F_SETFD, 1); /* set close-on-exec flag */
|
||||
/* We want to own this file, and set its mode to 0600. This is necessary
|
||||
* in order to prevent other users from putting locks on it. */
|
||||
if (fchown(jr->timestamp_fd, getuid(), getgid()))
|
||||
die_e("Can't chown timestamp file %s", jr->ident);
|
||||
if (fchmod(jr->timestamp_fd, S_IRUSR | S_IWUSR))
|
||||
die_e("Can't chmod timestamp file %s", jr->ident);
|
||||
}
|
||||
|
||||
static int
|
||||
lock_file(int fd)
|
||||
/* Attempt to put an exclusive fcntl() lock on file "fd"
|
||||
* Return 1 on success, 0 on failure.
|
||||
*/
|
||||
{
|
||||
int r;
|
||||
struct flock sfl;
|
||||
|
||||
sfl.l_type = F_WRLCK;
|
||||
sfl.l_start = 0;
|
||||
sfl.l_whence = SEEK_SET;
|
||||
sfl.l_len = 0; /* we lock all the file */
|
||||
errno = 0;
|
||||
r = fcntl(fd, F_SETLK, &sfl);
|
||||
if (r != -1) return 1;
|
||||
if (errno != EACCES && errno != EAGAIN)
|
||||
die_e("fcntl() error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
consider_job(job_rec *jr)
|
||||
/* Check the timestamp of the job. If "its time has come", lock the job
|
||||
* and return 1, if it's too early, or we can't get the lock, return 0.
|
||||
*/
|
||||
{
|
||||
char timestamp[9];
|
||||
int ts_year, ts_month, ts_day, dn;
|
||||
ssize_t b;
|
||||
|
||||
open_tsfile(jr);
|
||||
|
||||
/* read timestamp */
|
||||
b = read(jr->timestamp_fd, timestamp, 8);
|
||||
if (b == -1) die_e("Error reading timestamp file %s", jr->ident);
|
||||
timestamp[8] = 0;
|
||||
|
||||
/* is it too early? */
|
||||
if (!force && b == 8)
|
||||
{
|
||||
int day_delta;
|
||||
time_t jobtime;
|
||||
struct tm *t;
|
||||
|
||||
if (sscanf(timestamp, "%4d%2d%2d", &ts_year, &ts_month, &ts_day) == 3)
|
||||
dn = day_num(ts_year, ts_month, ts_day);
|
||||
else
|
||||
dn = 0;
|
||||
|
||||
day_delta = day_now - dn;
|
||||
|
||||
/*
|
||||
* if day_delta is negative, we assume there was a clock skew
|
||||
* and re-run any affected jobs
|
||||
* otherwise we check if the job's time has come
|
||||
*/
|
||||
if (day_delta >= 0 && day_delta < jr->period)
|
||||
{
|
||||
/* yes, skip job */
|
||||
xclose(jr->timestamp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if it's a named period, in which case we need
|
||||
* to figure it out.
|
||||
*/
|
||||
if (jr->named_period)
|
||||
{
|
||||
int period = 0, bypass = 0;
|
||||
switch (jr->named_period)
|
||||
{
|
||||
case 1: /* monthly */
|
||||
period = days_last_month ();
|
||||
bypass = days_this_month ();
|
||||
break;
|
||||
case 2: /* yearly, annually */
|
||||
period = days_last_year ();
|
||||
bypass = days_this_year ();
|
||||
break;
|
||||
case 3: /* daily */
|
||||
period = 1;
|
||||
bypass = 1;
|
||||
break;
|
||||
case 4: /* weekly */
|
||||
period = 7;
|
||||
bypass = 7;
|
||||
break;
|
||||
default:
|
||||
die ("Unknown named period for %s (%d)", jr->ident, jr->named_period);
|
||||
}
|
||||
printf ("Checking against %d with %d\n", day_delta, period);
|
||||
if (day_delta < period && day_delta != bypass)
|
||||
{
|
||||
/* Job is still too young */
|
||||
xclose (jr->timestamp_fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
jobtime = start_sec + jr->delay * 60;
|
||||
|
||||
t = localtime(&jobtime);
|
||||
if (!now && preferred_hour != -1 && t->tm_hour != preferred_hour) {
|
||||
Debug(("The job's %s preferred hour %d was missed, skipping the job.", jr->ident, preferred_hour));
|
||||
xclose (jr->timestamp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!now && range_start != -1 && range_stop != -1 &&
|
||||
(t->tm_hour < range_start || t->tm_hour >= range_stop))
|
||||
{
|
||||
Debug(("The job `%s' falls out of the %02d:00-%02d:00 hours range, skipping.",
|
||||
jr->ident, range_start, range_stop));
|
||||
xclose (jr->timestamp_fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* no! try to grab the lock */
|
||||
if (lock_file(jr->timestamp_fd)) return 1; /* success */
|
||||
|
||||
/* didn't get lock */
|
||||
xclose(jr->timestamp_fd);
|
||||
explain("Job `%s' locked by another anacron - skipping", jr->ident);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
unlock(job_rec *jr)
|
||||
{
|
||||
xclose(jr->timestamp_fd);
|
||||
}
|
||||
|
||||
void
|
||||
update_timestamp(job_rec *jr)
|
||||
/* We write the date "now". "Now" can be either the time when anacron
|
||||
* started, or the time when the job finished.
|
||||
* I'm not quite sure which is more "right", but I've decided on the first
|
||||
* option.
|
||||
* Note that this is not the way it was with anacron 1.0.3 to 1.0.7.
|
||||
*/
|
||||
{
|
||||
char stamp[10];
|
||||
|
||||
snprintf(stamp, 10, "%04d%02d%02d\n", year, month, day_of_month);
|
||||
if (lseek(jr->timestamp_fd, 0, SEEK_SET))
|
||||
die_e("Can't lseek timestamp file for job %s", jr->ident);
|
||||
if (write(jr->timestamp_fd, stamp, 9) != 9)
|
||||
die_e("Can't write timestamp file for job %s", jr->ident);
|
||||
if (ftruncate(jr->timestamp_fd, 9))
|
||||
die_e("ftruncate error");
|
||||
}
|
||||
|
||||
void
|
||||
fake_job(job_rec *jr)
|
||||
/* We don't bother with any locking here. There's no point. */
|
||||
{
|
||||
open_tsfile(jr);
|
||||
update_timestamp(jr);
|
||||
xclose(jr->timestamp_fd);
|
||||
}
|
230
anacron/log.c
Normal file
230
anacron/log.c
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
/* Error logging
|
||||
*
|
||||
* We have two levels of logging (plus debugging if DEBUG is defined):
|
||||
* "explain" level for informational messages, and "complain" level for errors.
|
||||
*
|
||||
* We log everything to syslog, see the top of global.h for relevant
|
||||
* definitions.
|
||||
*
|
||||
* Stderr gets "complain" messages when we're in the foreground,
|
||||
* and "explain" messages when we're in the foreground, and not "quiet".
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "global.h"
|
||||
|
||||
static char truncated[] = " (truncated)";
|
||||
static char msg[MAX_MSG + 1];
|
||||
static int log_open = 0;
|
||||
|
||||
/* Number of complaints that we've seen */
|
||||
int complaints = 0;
|
||||
|
||||
static void
|
||||
xopenlog(void)
|
||||
{
|
||||
if (!log_open)
|
||||
{
|
||||
openlog(program_name, LOG_PID, SYSLOG_FACILITY);
|
||||
log_open = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xcloselog(void)
|
||||
{
|
||||
if (log_open) closelog();
|
||||
log_open = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
make_msg(const char *fmt, va_list args)
|
||||
/* Construct the message string from its parts */
|
||||
{
|
||||
int len;
|
||||
|
||||
/* There's some confusion in the documentation about what vsnprintf
|
||||
* returns when the buffer overflows. Hmmm... */
|
||||
len = vsnprintf(msg, sizeof(msg), fmt, args);
|
||||
if (len < 0) {
|
||||
strncpy(msg, "(vsnprintf failed)", sizeof(msg));
|
||||
msg[sizeof(msg) - 1] = '\0';
|
||||
return;
|
||||
}
|
||||
if ((size_t) len >= sizeof(msg) - 1)
|
||||
strcpy(msg + sizeof(msg) - sizeof(truncated), truncated);
|
||||
}
|
||||
|
||||
static void
|
||||
slog(int priority, const char *fmt, va_list args)
|
||||
/* Log a message, described by "fmt" and "args", with the specified
|
||||
* "priority". */
|
||||
{
|
||||
make_msg(fmt, args);
|
||||
xopenlog();
|
||||
syslog(priority, "%s", msg);
|
||||
if (!in_background)
|
||||
{
|
||||
if (priority == EXPLAIN_LEVEL && !quiet)
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
else if (priority == COMPLAIN_LEVEL)
|
||||
fprintf(stderr, "%s: %s\n", program_name, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
log_e(int priority, const char *fmt, va_list args)
|
||||
/* Same as slog(), but also appends an error description corresponding
|
||||
* to "errno". */
|
||||
{
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
make_msg(fmt, args);
|
||||
xopenlog();
|
||||
syslog(priority, "%s: %s", msg, strerror(saved_errno));
|
||||
if (!in_background)
|
||||
{
|
||||
if (priority == EXPLAIN_LEVEL && !quiet)
|
||||
fprintf(stderr, "%s: %s\n", msg, strerror(saved_errno));
|
||||
else if (priority == COMPLAIN_LEVEL)
|
||||
fprintf(stderr, "%s: %s: %s\n",
|
||||
program_name, msg, strerror(saved_errno));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
explain(const char *fmt, ...)
|
||||
/* Log an "explain" level message */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
slog(EXPLAIN_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
explain_e(const char *fmt, ...)
|
||||
/* Log an "explain" level message, with an error description */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
log_e(EXPLAIN_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
complain(const char *fmt, ...)
|
||||
/* Log a "complain" level message */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
slog(COMPLAIN_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
complaints += 1;
|
||||
}
|
||||
|
||||
void
|
||||
complain_e(const char *fmt, ...)
|
||||
/* Log a "complain" level message, with an error description */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
log_e(COMPLAIN_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
complaints += 1;
|
||||
}
|
||||
|
||||
void
|
||||
die(const char *fmt, ...)
|
||||
/* Log a "complain" level message, and exit */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
slog(COMPLAIN_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
if (getpid() == primary_pid) complain("Aborted");
|
||||
|
||||
exit(FAILURE_EXIT);
|
||||
}
|
||||
|
||||
void
|
||||
die_e(const char *fmt, ...)
|
||||
/* Log a "complain" level message, with an error description, and exit */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
log_e(COMPLAIN_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
if (getpid() == primary_pid) complain("Aborted");
|
||||
|
||||
exit(FAILURE_EXIT);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* These are called through the Debug() and Debug_e() macros, defined
|
||||
* in global.h */
|
||||
|
||||
void
|
||||
xdebug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
slog(DEBUG_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
xdebug_e(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
log_e(DEBUG_LEVEL, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
517
anacron/main.c
Normal file
517
anacron/main.c
Normal file
@ -0,0 +1,517 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#include "global.h"
|
||||
#include "gregor.h"
|
||||
#include "cronie_common.h"
|
||||
|
||||
pid_t primary_pid;
|
||||
int day_now;
|
||||
int year, month, day_of_month; /* date anacron started */
|
||||
|
||||
char *program_name;
|
||||
char *anacrontab = NULL;
|
||||
char *spooldir = NULL;
|
||||
int serialize, force, update_only, now,
|
||||
no_daemon, quiet, testing_only; /* command-line options */
|
||||
char **job_args; /* vector of "job" command-line arguments */
|
||||
int job_nargs; /* number of these */
|
||||
char *defarg = "*";
|
||||
int in_background; /* are we in the background? */
|
||||
sigset_t old_sigmask; /* signal mask when started */
|
||||
|
||||
job_rec *first_job_rec;
|
||||
env_rec *first_env_rec;
|
||||
|
||||
time_t start_sec; /* time anacron started */
|
||||
static volatile int got_sigalrm, got_sigchld, got_sigusr1;
|
||||
int running_jobs, running_mailers; /* , number of */
|
||||
int range_start = -1;
|
||||
int range_stop = -1;
|
||||
int preferred_hour = -1;
|
||||
|
||||
static void
|
||||
print_version(void)
|
||||
{
|
||||
printf("Anacron from project %s\n"
|
||||
"Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>\n"
|
||||
"Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>\n"
|
||||
"Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>\n"
|
||||
"\n"
|
||||
"Mail comments, suggestions and bug reports to <pasc@redellipse.net>."
|
||||
"\n\n", PACKAGE_STRING);
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage(void)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" %s [options] [job] ...\n", program_name);
|
||||
printf(" %s -T [-t anacrontab-file]\n", program_name);
|
||||
printf("\nOptions:\n");
|
||||
printf(" -s Serialize execution of jobs\n");
|
||||
printf(" -f Force execution of jobs, even before their time\n");
|
||||
printf(" -n Run jobs with no delay, implies -s\n");
|
||||
printf(" -d Don't fork to the background\n");
|
||||
printf(" -q Suppress stderr messages, only applicable with -d\n");
|
||||
printf(" -u Update the timestamps without actually running anything\n");
|
||||
printf(" -V Print version information\n");
|
||||
printf(" -h Print this message\n");
|
||||
printf(" -t <file> Use alternative anacrontab\n");
|
||||
printf(" -T Test an anacrontab\n");
|
||||
printf(" -S <dir> Select a different spool directory\n");
|
||||
printf("\nSee the anacron(8) manpage for more details.\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_opts(int argc, char *argv[])
|
||||
/* Parse command-line options */
|
||||
{
|
||||
int opt;
|
||||
|
||||
quiet = no_daemon = serialize = force = update_only = now = 0;
|
||||
opterr = 0;
|
||||
while ((opt = getopt(argc, argv, "sfundqt:TS:Vh")) != EOF)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
serialize = 1;
|
||||
break;
|
||||
case 'f':
|
||||
force = 1;
|
||||
break;
|
||||
case 'u':
|
||||
update_only = 1;
|
||||
break;
|
||||
case 'n':
|
||||
now = serialize = 1;
|
||||
break;
|
||||
case 'd':
|
||||
no_daemon = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 't':
|
||||
free(anacrontab);
|
||||
anacrontab = strdup(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
testing_only = 1;
|
||||
break;
|
||||
case 'S':
|
||||
free(spooldir);
|
||||
spooldir = strdup(optarg);
|
||||
break;
|
||||
case 'V':
|
||||
print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
fprintf(stderr, "%s: invalid option: %c\n",
|
||||
program_name, optopt);
|
||||
fprintf(stderr, "type: `%s -h' for more information\n",
|
||||
program_name);
|
||||
exit(FAILURE_EXIT);
|
||||
}
|
||||
}
|
||||
if (optind == argc)
|
||||
{
|
||||
/* no arguments. Equivalent to: `*' */
|
||||
job_nargs = 1;
|
||||
job_args = &defarg;
|
||||
}
|
||||
else
|
||||
{
|
||||
job_nargs = argc - optind;
|
||||
job_args = argv + optind;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t
|
||||
xfork(void)
|
||||
/* Like fork(), only never returns on failure */
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) die_e("Can't fork");
|
||||
return pid;
|
||||
}
|
||||
|
||||
int
|
||||
xopen(int fd, const char *file_name, int flags)
|
||||
/* Like open, only it:
|
||||
* a) never returns on failure, and
|
||||
* b) if "fd" is non-negative, expect the file to open
|
||||
* on file-descriptor "fd".
|
||||
*/
|
||||
{
|
||||
int rfd;
|
||||
|
||||
rfd = open(file_name, flags);
|
||||
if (fd >= 0 && rfd != fd)
|
||||
die_e("Can't open %s on file-descriptor %d", file_name, fd);
|
||||
else if (rfd < 0)
|
||||
die_e("Can't open %s", file_name);
|
||||
return rfd;
|
||||
}
|
||||
|
||||
void
|
||||
xclose(int fd)
|
||||
/* Like close(), only doesn't return on failure */
|
||||
{
|
||||
if (close(fd)) die_e("Can't close file descriptor %d", fd);
|
||||
}
|
||||
|
||||
static void
|
||||
go_background(void)
|
||||
/* Become a daemon. The foreground process exits successfully. */
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
/* stdin is already closed */
|
||||
|
||||
if (fclose(stdout)) die_e("Can't close stdout");
|
||||
/* coverity[leaked_handle] – fd 1 closed automatically */
|
||||
xopen(1, "/dev/null", O_WRONLY);
|
||||
|
||||
if (fclose(stderr)) die_e("Can't close stderr");
|
||||
/* coverity[leaked_handle] – fd 2 closed automatically */
|
||||
xopen(2, "/dev/null", O_WRONLY);
|
||||
|
||||
pid = xfork();
|
||||
if (pid != 0)
|
||||
{
|
||||
/* parent */
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* child */
|
||||
primary_pid = getpid();
|
||||
if (setsid() == -1) die_e("setsid() error");
|
||||
in_background = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sigalrm(int unused ATTRIBUTE_UNUSED)
|
||||
{
|
||||
got_sigalrm = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sigchld(int unused ATTRIBUTE_UNUSED)
|
||||
{
|
||||
got_sigchld = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sigusr1(int unused ATTRIBUTE_UNUSED)
|
||||
{
|
||||
got_sigusr1 = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
set_signal_handling(void)
|
||||
/* We only use SIGALRM, SIGCHLD and SIGUSR1, and we unblock them only
|
||||
* in wait_signal().
|
||||
*/
|
||||
{
|
||||
sigset_t ss;
|
||||
struct sigaction sa;
|
||||
|
||||
got_sigalrm = got_sigchld = got_sigusr1 = 0;
|
||||
|
||||
/* block SIGALRM, SIGCHLD and SIGUSR1 */
|
||||
if (sigemptyset(&ss) ||
|
||||
sigaddset(&ss, SIGALRM) ||
|
||||
sigaddset(&ss, SIGCHLD) ||
|
||||
sigaddset(&ss, SIGUSR1)) die_e("sigset error");
|
||||
if (sigprocmask(SIG_BLOCK, &ss, NULL)) die_e ("sigprocmask error");
|
||||
|
||||
/* setup SIGALRM handler */
|
||||
sa.sa_handler = handle_sigalrm;
|
||||
sa.sa_mask = ss;
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(SIGALRM, &sa, NULL)) die_e("sigaction error");
|
||||
|
||||
/* setup SIGCHLD handler */
|
||||
sa.sa_handler = handle_sigchld;
|
||||
sa.sa_mask = ss;
|
||||
sa.sa_flags = SA_NOCLDSTOP;
|
||||
if (sigaction(SIGCHLD, &sa, NULL)) die_e("sigaction error");
|
||||
|
||||
/* setup SIGUSR1 handler */
|
||||
sa.sa_handler = handle_sigusr1;
|
||||
sa.sa_mask = ss;
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(SIGUSR1, &sa, NULL)) die_e("sigaction error");
|
||||
}
|
||||
|
||||
static void
|
||||
wait_signal(void)
|
||||
/* Return after a signal is caught */
|
||||
{
|
||||
sigset_t ss;
|
||||
|
||||
if (sigprocmask(0, NULL, &ss)) die_e("sigprocmask error");
|
||||
if (sigdelset(&ss, SIGALRM) ||
|
||||
sigdelset(&ss, SIGCHLD) ||
|
||||
sigdelset(&ss, SIGUSR1)) die_e("sigset error");
|
||||
sigsuspend(&ss);
|
||||
}
|
||||
|
||||
static void
|
||||
wait_children(void)
|
||||
/* Wait until we have no more children (of any kind) */
|
||||
{
|
||||
while (running_jobs > 0 || running_mailers > 0)
|
||||
{
|
||||
wait_signal();
|
||||
if (got_sigchld) tend_children();
|
||||
got_sigchld = 0;
|
||||
if (got_sigusr1) explain("Received SIGUSR1");
|
||||
got_sigusr1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
orderly_termination(void)
|
||||
/* Execution is diverted here, when we get SIGUSR1 */
|
||||
{
|
||||
explain("Received SIGUSR1");
|
||||
got_sigusr1 = 0;
|
||||
wait_children();
|
||||
explain("Exited");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
xsleep(unsigned int n)
|
||||
/* Sleep for n seconds, servicing SIGCHLDs and SIGUSR1s in the meantime.
|
||||
* If n=0, return immediately.
|
||||
*/
|
||||
{
|
||||
if (n == 0) return;
|
||||
alarm(n);
|
||||
do
|
||||
{
|
||||
wait_signal();
|
||||
if (got_sigchld) tend_children();
|
||||
got_sigchld = 0;
|
||||
if (got_sigusr1) orderly_termination();
|
||||
}
|
||||
while (!got_sigalrm);
|
||||
got_sigalrm = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
wait_jobs(void)
|
||||
/* Wait until there are no running jobs,
|
||||
* servicing SIGCHLDs and SIGUSR1s in the meantime.
|
||||
*/
|
||||
{
|
||||
while (running_jobs > 0)
|
||||
{
|
||||
wait_signal();
|
||||
if (got_sigchld) tend_children();
|
||||
got_sigchld = 0;
|
||||
if (got_sigusr1) orderly_termination();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
record_start_time(void)
|
||||
{
|
||||
struct tm *tm_now;
|
||||
|
||||
start_sec = time(NULL);
|
||||
tm_now = localtime(&start_sec);
|
||||
year = tm_now->tm_year + 1900;
|
||||
month = tm_now->tm_mon + 1;
|
||||
day_of_month = tm_now->tm_mday;
|
||||
day_now = day_num(year, month, day_of_month);
|
||||
if (day_now == -1) die("Invalid date (this is really embarrassing)");
|
||||
if (!update_only && !testing_only)
|
||||
explain("Anacron started on %04d-%02d-%02d",
|
||||
year, month, day_of_month);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
time_till(job_rec *jr)
|
||||
/* Return the number of seconds that we have to wait until it's time
|
||||
* to start job jr.
|
||||
*/
|
||||
{
|
||||
time_t tj, tn;
|
||||
|
||||
if (now) return 0;
|
||||
tn = time(NULL);
|
||||
tj = start_sec + (time_t)jr->delay * 60;
|
||||
if (tj < tn) return 0;
|
||||
if (tj - tn > 3600*24)
|
||||
{
|
||||
explain("System time manipulation detected, job `%s' will run immediately",
|
||||
jr->ident);
|
||||
return 0;
|
||||
}
|
||||
return (unsigned int)(tj - tn);
|
||||
}
|
||||
|
||||
static void
|
||||
fake_jobs(void)
|
||||
{
|
||||
int j;
|
||||
|
||||
j = 0;
|
||||
while (j < njobs)
|
||||
{
|
||||
fake_job(job_array[j]);
|
||||
explain("Updated timestamp for job `%s' to %04d-%02d-%02d",
|
||||
job_array[j]->ident, year, month, day_of_month);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
explain_intentions(void)
|
||||
{
|
||||
int j;
|
||||
|
||||
j = 0;
|
||||
while (j < njobs)
|
||||
{
|
||||
if (now)
|
||||
{
|
||||
explain("Will run job `%s'", job_array[j]->ident);
|
||||
}
|
||||
else
|
||||
{
|
||||
explain("Will run job `%s' in %d min.",
|
||||
job_array[j]->ident, job_array[j]->delay);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (serialize && njobs > 0)
|
||||
explain("Jobs will be executed sequentially");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int j;
|
||||
int cwd;
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
anacrontab = NULL;
|
||||
spooldir = NULL;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
if (gettimeofday(&tv, &tz) != 0)
|
||||
explain("Can't get exact time, failure.");
|
||||
|
||||
srandom((unsigned int)(getpid() + tv.tv_usec));
|
||||
|
||||
if((program_name = strrchr(argv[0], '/')) == NULL)
|
||||
program_name = argv[0];
|
||||
else
|
||||
++program_name; /* move pointer to char after '/' */
|
||||
|
||||
parse_opts(argc, argv);
|
||||
|
||||
if (anacrontab == NULL)
|
||||
anacrontab = strdup(ANACRONTAB);
|
||||
|
||||
if (spooldir == NULL)
|
||||
spooldir = strdup(ANACRON_SPOOL_DIR);
|
||||
|
||||
if ((cwd = open ("./", O_RDONLY)) == -1) {
|
||||
die_e ("Can't save current directory");
|
||||
}
|
||||
|
||||
in_background = 0;
|
||||
|
||||
if (chdir(spooldir)) die_e("Can't chdir to %s", spooldir );
|
||||
|
||||
if (sigprocmask(0, NULL, &old_sigmask)) die_e("sigset error");
|
||||
|
||||
if (fclose(stdin)) die_e("Can't close stdin");
|
||||
xopen(STDIN_FILENO, "/dev/null", O_RDONLY);
|
||||
|
||||
if (!no_daemon && !testing_only)
|
||||
go_background();
|
||||
else
|
||||
primary_pid = getpid();
|
||||
|
||||
record_start_time();
|
||||
read_tab(cwd);
|
||||
close(cwd);
|
||||
arrange_jobs();
|
||||
|
||||
if (testing_only)
|
||||
{
|
||||
if (complaints) exit (EXIT_FAILURE);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (update_only)
|
||||
{
|
||||
fake_jobs();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
explain_intentions();
|
||||
set_signal_handling();
|
||||
running_jobs = running_mailers = 0;
|
||||
for(j = 0; j < njobs; ++j)
|
||||
{
|
||||
xsleep(time_till(job_array[j]));
|
||||
if (serialize) wait_jobs();
|
||||
launch_job(job_array[j]);
|
||||
}
|
||||
wait_children();
|
||||
explain("Normal exit (%d job%s run)", njobs, njobs == 1 ? "" : "s");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
92
anacron/matchrx.c
Normal file
92
anacron/matchrx.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "matchrx.h"
|
||||
|
||||
int
|
||||
match_rx(const char *rx, char *string, unsigned int n_sub, /* char **substrings */...)
|
||||
/* Return 1 if the regular expression "*rx" matches the string "*string",
|
||||
* 0 if not, -1 on error.
|
||||
* "Extended" regular expressions are used.
|
||||
* Additionally, there should be "n_sub" "substrings" arguments. These,
|
||||
* if not NULL, and if the match succeeds are set to point to the
|
||||
* corresponding substrings of the regexp.
|
||||
* The original string is changed, and the substrings must not overlap,
|
||||
* or even be directly adjacent.
|
||||
* This is not the most efficient, or elegant way of doing this.
|
||||
*/
|
||||
{
|
||||
int r;
|
||||
unsigned int n;
|
||||
regex_t crx;
|
||||
va_list va;
|
||||
char **substring;
|
||||
regmatch_t *sub_offsets;
|
||||
|
||||
sub_offsets = malloc(sizeof(regmatch_t) * (n_sub + 1));
|
||||
if (sub_offsets == NULL)
|
||||
return -1;
|
||||
memset(sub_offsets, 0, sizeof(regmatch_t) * (n_sub + 1));
|
||||
|
||||
if (regcomp(&crx, rx, REG_EXTENDED)) {
|
||||
free(sub_offsets);
|
||||
return -1;
|
||||
}
|
||||
r = regexec(&crx, string, n_sub + 1, sub_offsets, 0);
|
||||
if (r != 0 && r != REG_NOMATCH) {
|
||||
free(sub_offsets);
|
||||
return -1;
|
||||
}
|
||||
regfree(&crx);
|
||||
if (r == REG_NOMATCH) {
|
||||
free(sub_offsets);
|
||||
return 0;
|
||||
}
|
||||
|
||||
va_start(va, n_sub);
|
||||
n = 1;
|
||||
while (n <= n_sub)
|
||||
{
|
||||
substring = va_arg(va, char**);
|
||||
if (substring != NULL)
|
||||
{
|
||||
if (sub_offsets[n].rm_so == -1) {
|
||||
va_end(va);
|
||||
free(sub_offsets);
|
||||
return - 1;
|
||||
}
|
||||
*substring = string + sub_offsets[n].rm_so;
|
||||
*(string + sub_offsets[n].rm_eo) = 0;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
va_end(va);
|
||||
free(sub_offsets);
|
||||
return 1;
|
||||
}
|
26
anacron/matchrx.h
Normal file
26
anacron/matchrx.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
int match_rx(const char *rx, char *string,
|
||||
unsigned int n_sub, /* char **substrings */...);
|
451
anacron/readtab.c
Normal file
451
anacron/readtab.c
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
Copyright (C) 2004 Pascal Hakim <pasc@redellipse.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
/* /etc/anacrontab parsing, and job sorting
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <obstack.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include "global.h"
|
||||
#include "matchrx.h"
|
||||
|
||||
static struct obstack input_o; /* holds input line */
|
||||
static struct obstack tab_o; /* holds processed data read from anacrontab */
|
||||
static FILE *tab;
|
||||
job_rec **job_array;
|
||||
int njobs; /* number of jobs to run */
|
||||
static int jobs_read; /* number of jobs read */
|
||||
static int line_num; /* current line in anacrontab */
|
||||
static job_rec *last_job_rec; /* last job stored in memory, at the moment */
|
||||
static env_rec *last_env_rec; /* last environment assignment stored */
|
||||
|
||||
static int random_number = 0;
|
||||
|
||||
/* some definitions for the obstack macros */
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free free
|
||||
|
||||
static void *
|
||||
xmalloc (size_t size)
|
||||
/* Just like standard malloc(), only never returns NULL. */
|
||||
{
|
||||
void * ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
die("Memory exhausted");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
conv2int(const char *s)
|
||||
/* Return the int or -1 on over/under-flow
|
||||
*/
|
||||
{
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(s, NULL, 10);
|
||||
/* we use negative as error, so I am really returning unsigned int */
|
||||
if (errno == ERANGE || l < 0 || l > INT_MAX) return - 1;
|
||||
return (int)l;
|
||||
}
|
||||
|
||||
static char *
|
||||
read_tab_line (void)
|
||||
/* Read one line and return a pointer to it.
|
||||
Return NULL if no more lines.
|
||||
*/
|
||||
{
|
||||
int c, prev=0;
|
||||
|
||||
if (feof(tab)) return NULL;
|
||||
while (1)
|
||||
{
|
||||
c = getc(tab);
|
||||
if ((c == '\n' && prev != '\\') || c == EOF)
|
||||
{
|
||||
if (0 != prev) obstack_1grow(&input_o, (char)prev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (('\\' != prev || c != '\n') && 0 != prev && '\n' != prev) obstack_1grow(&input_o, (char)prev);
|
||||
else if ('\n' == prev) obstack_1grow(&input_o, ' ');
|
||||
|
||||
prev = c;
|
||||
}
|
||||
if (ferror(tab)) die_e("Error reading %s", anacrontab);
|
||||
obstack_1grow(&input_o, '\0');
|
||||
return obstack_finish(&input_o);
|
||||
}
|
||||
|
||||
static int
|
||||
job_arg_num(const char *ident)
|
||||
/* Return the command-line-argument number referring to this job-identifier.
|
||||
* If it isn't specified, return -1.
|
||||
*/
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < job_nargs; i++)
|
||||
{
|
||||
r = fnmatch(job_args[i], ident, 0);
|
||||
if (r == 0) return i;
|
||||
if (r != FNM_NOMATCH) die("fnmatch() error");
|
||||
}
|
||||
return - 1;
|
||||
}
|
||||
|
||||
static void
|
||||
register_env(const char *env_var, const char *value)
|
||||
/* Store the environment assignment "env_var"="value" */
|
||||
{
|
||||
env_rec *er;
|
||||
int var_len, val_len;
|
||||
|
||||
var_len = (int)strlen(env_var);
|
||||
val_len = (int)strlen(value);
|
||||
if (!var_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
er = obstack_alloc(&tab_o, sizeof(env_rec));
|
||||
if (er == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
|
||||
er->assign = obstack_alloc(&tab_o, var_len + 1 + val_len + 1);
|
||||
if (er->assign == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
strcpy(er->assign, env_var);
|
||||
er->assign[var_len] = '=';
|
||||
strcpy(er->assign + var_len + 1, value);
|
||||
er->assign[var_len + 1 + val_len] = 0;
|
||||
if (last_env_rec != NULL) last_env_rec->next = er;
|
||||
else first_env_rec = er;
|
||||
last_env_rec = er;
|
||||
Debug(("on line %d: %s", line_num, er->assign));
|
||||
}
|
||||
|
||||
static void
|
||||
register_job(const char *periods, const char *delays,
|
||||
const char *ident, char *command)
|
||||
/* Store a job definition */
|
||||
{
|
||||
int period, delay;
|
||||
job_rec *jr;
|
||||
int ident_len, command_len;
|
||||
|
||||
ident_len = (int)strlen(ident);
|
||||
command_len = (int)strlen(command);
|
||||
jobs_read++;
|
||||
period = conv2int(periods);
|
||||
delay = conv2int(delays);
|
||||
if (period < 0 || delay < 0)
|
||||
{
|
||||
complain("%s: number out of range on line %d, skipping",
|
||||
anacrontab, line_num);
|
||||
return;
|
||||
}
|
||||
jr = obstack_alloc(&tab_o, sizeof(job_rec));
|
||||
if (jr == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
jr->period = period;
|
||||
jr->named_period = 0;
|
||||
delay += random_number;
|
||||
jr->delay = delay;
|
||||
jr->tab_line = line_num;
|
||||
jr->ident = obstack_alloc(&tab_o, ident_len + 1);
|
||||
if (jr->ident == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
strcpy(jr->ident, ident);
|
||||
jr->arg_num = job_arg_num(ident);
|
||||
jr->command = obstack_alloc(&tab_o, command_len + 1);
|
||||
if (jr->command == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
strcpy(jr->command, command);
|
||||
jr->job_pid = jr->mailer_pid = 0;
|
||||
if (last_job_rec != NULL) last_job_rec->next = jr;
|
||||
else first_job_rec = jr;
|
||||
last_job_rec = jr;
|
||||
jr->prev_env_rec = last_env_rec;
|
||||
jr->next = NULL;
|
||||
Debug(("Read job - period=%d, delay=%d, ident=%s, command=%s",
|
||||
jr->period, jr->delay, jr->ident, jr->command));
|
||||
}
|
||||
|
||||
static void
|
||||
register_period_job(const char *periods, const char *delays,
|
||||
const char *ident, char *command)
|
||||
/* Store a job definition with a named period */
|
||||
{
|
||||
int delay;
|
||||
job_rec *jr;
|
||||
int ident_len, command_len;
|
||||
|
||||
ident_len = (int)strlen(ident);
|
||||
command_len = (int)strlen(command);
|
||||
jobs_read++;
|
||||
delay = conv2int(delays);
|
||||
if (delay < 0)
|
||||
{
|
||||
complain("%s: number out of range on line %d, skipping",
|
||||
anacrontab, line_num);
|
||||
return;
|
||||
}
|
||||
|
||||
jr = obstack_alloc(&tab_o, sizeof(job_rec));
|
||||
if (jr == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
if (!strncmp ("@monthly", periods, 8)) {
|
||||
jr->named_period = 1;
|
||||
} else if (!strncmp("@yearly", periods, 7) || !strncmp("@annually", periods, 9) || !strncmp(/* backwards compat misspelling */"@annualy", periods, 8)) {
|
||||
jr->named_period = 2;
|
||||
} else if (!strncmp ("@daily", periods, 6)) {
|
||||
jr->named_period = 3;
|
||||
} else if (!strncmp ("@weekly", periods, 7)) {
|
||||
jr->named_period = 4;
|
||||
} else {
|
||||
complain("%s: Unknown named period on line %d, skipping",
|
||||
anacrontab, line_num);
|
||||
}
|
||||
jr->period = 0;
|
||||
delay += random_number;
|
||||
jr->delay = delay;
|
||||
jr->tab_line = line_num;
|
||||
jr->ident = obstack_alloc(&tab_o, ident_len + 1);
|
||||
if (jr->ident == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
strcpy(jr->ident, ident);
|
||||
jr->arg_num = job_arg_num(ident);
|
||||
jr->command = obstack_alloc(&tab_o, command_len + 1);
|
||||
if (jr->command == NULL) {
|
||||
die_e("Cannot allocate memory.");
|
||||
}
|
||||
strcpy(jr->command, command);
|
||||
jr->job_pid = jr->mailer_pid = 0;
|
||||
if (last_job_rec != NULL) last_job_rec->next = jr;
|
||||
else first_job_rec = jr;
|
||||
last_job_rec = jr;
|
||||
jr->prev_env_rec = last_env_rec;
|
||||
jr->next = NULL;
|
||||
Debug(("Read job - period %d, delay=%d, ident%s, command=%s",
|
||||
jr->named_period, jr->delay, jr->ident, jr->command));
|
||||
}
|
||||
|
||||
static long int
|
||||
unbiased_rand(long int max)
|
||||
{
|
||||
long int rn;
|
||||
long int divisor;
|
||||
|
||||
divisor = RAND_MAX / (max + 1);
|
||||
|
||||
do {
|
||||
rn = random() / divisor;
|
||||
} while (rn > max);
|
||||
|
||||
return rn;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_tab_line(char *line)
|
||||
{
|
||||
int r;
|
||||
char *env_var;
|
||||
char *value;
|
||||
char *periods;
|
||||
char *delays;
|
||||
char *ident;
|
||||
char *command;
|
||||
char *from;
|
||||
char *to;
|
||||
char *pref_hour;
|
||||
|
||||
/* an empty line? */
|
||||
r = match_rx("^[ \t]*($|#)", line, 0);
|
||||
if (r == -1) goto reg_err;
|
||||
if (r)
|
||||
{
|
||||
Debug(("line %d empty", line_num));
|
||||
return;
|
||||
}
|
||||
|
||||
/* an environment assignment? */
|
||||
r = match_rx("^[ \t]*([^ \t=]+)[ \t]*=(.*)$", line, 2,
|
||||
&env_var, &value);
|
||||
if (r == -1) goto reg_err;
|
||||
if (r)
|
||||
{
|
||||
if (strncmp(env_var, "START_HOURS_RANGE", 17) == 0)
|
||||
{
|
||||
r = match_rx("^([[:digit:]]+)-([[:digit:]]+)$", value, 2, &from, &to);
|
||||
if (r == -1) goto reg_err;
|
||||
if (r == 0) goto reg_invalid;
|
||||
range_start = atoi(from);
|
||||
range_stop = atoi(to);
|
||||
if (range_stop < range_start) {
|
||||
range_start = 0; range_stop = 0;
|
||||
goto reg_invalid;
|
||||
}
|
||||
Debug(("Jobs will start in the %02d:00-%02d:00 range.", range_start, range_stop));
|
||||
}
|
||||
else if (strncmp(env_var, "RANDOM_DELAY", 12) == 0) {
|
||||
r = match_rx("^([[:digit:]]+)$", value, 0);
|
||||
if (r == -1) goto reg_err;
|
||||
if (r == 0) goto reg_invalid;
|
||||
|
||||
random_number = (int)unbiased_rand(atoi(value));
|
||||
Debug(("Randomized delay set: %d", random_number));
|
||||
}
|
||||
else if (strncmp(env_var, "PREFERRED_HOUR", 14) == 0) {
|
||||
r = match_rx("^([[:digit:]]+)$", value, 1, &pref_hour);
|
||||
if (r == -1) goto reg_err;
|
||||
|
||||
if (r) {
|
||||
preferred_hour = atoi(pref_hour);
|
||||
if ((preferred_hour < 0) || (preferred_hour > 24)) {
|
||||
preferred_hour = -1;
|
||||
goto reg_invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
register_env(env_var, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* a job? */
|
||||
r = match_rx("^[ \t]*([[:digit:]]+)[ \t]+([[:digit:]]+)[ \t]+"
|
||||
"([^ \t/]+)[ \t]+([^ \t].*)$",
|
||||
line, 4, &periods, &delays, &ident, &command);
|
||||
if (r == -1) goto reg_err;
|
||||
if (r)
|
||||
{
|
||||
register_job(periods, delays, ident, command);
|
||||
return;
|
||||
}
|
||||
|
||||
/* A period job? */
|
||||
r = match_rx("^[ \t]*(@[^ \t]+)[ \t]+([[:digit:]]+)[ \t]+"
|
||||
"([^ \t/]+)[ \t]+([^ \t].*)$",
|
||||
line, 4, &periods, &delays, &ident, &command);
|
||||
if (r == -1) goto reg_err;
|
||||
if (r)
|
||||
{
|
||||
register_period_job(periods, delays, ident, command);
|
||||
return;
|
||||
}
|
||||
|
||||
reg_invalid:
|
||||
complain("Invalid syntax in %s on line %d - skipping this line",
|
||||
anacrontab, line_num);
|
||||
return;
|
||||
|
||||
reg_err:
|
||||
die("Regex error reading %s", anacrontab);
|
||||
}
|
||||
|
||||
void
|
||||
read_tab(int cwd)
|
||||
/* Read the anacrontab file into memory */
|
||||
{
|
||||
char *tab_line;
|
||||
|
||||
first_job_rec = last_job_rec = NULL;
|
||||
first_env_rec = last_env_rec = NULL;
|
||||
jobs_read = 0;
|
||||
line_num = 0;
|
||||
/* Open the anacrontab file */
|
||||
if (fchdir(cwd)) die_e("Can't chdir to original cwd");
|
||||
tab = fopen(anacrontab, "r");
|
||||
if (chdir(spooldir)) die_e("Can't chdir to %s", spooldir);
|
||||
|
||||
if (tab == NULL) die_e("Error opening %s", anacrontab);
|
||||
/* Initialize the obstacks */
|
||||
obstack_init(&input_o);
|
||||
obstack_init(&tab_o);
|
||||
while ((tab_line = read_tab_line()) != NULL)
|
||||
{
|
||||
line_num++;
|
||||
parse_tab_line(tab_line);
|
||||
obstack_free(&input_o, tab_line);
|
||||
}
|
||||
if (fclose(tab)) die_e("Error closing %s", anacrontab);
|
||||
}
|
||||
|
||||
static int
|
||||
execution_order(const job_rec **job1, const job_rec **job2)
|
||||
/* Comparison function for sorting the jobs.
|
||||
*/
|
||||
{
|
||||
int d;
|
||||
|
||||
d = (*job1)->arg_num - (*job2)->arg_num;
|
||||
if (d != 0 && now) return d;
|
||||
d = (*job1)->delay - (*job2)->delay;
|
||||
if (d != 0) return d;
|
||||
d = (*job1)->tab_line - (*job2)->tab_line;
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
arrange_jobs(void)
|
||||
/* Make an array of pointers to jobs that are going to be executed,
|
||||
* and arrange them in the order of execution.
|
||||
* Also lock these jobs.
|
||||
*/
|
||||
{
|
||||
job_rec *j;
|
||||
|
||||
j = first_job_rec;
|
||||
njobs = 0;
|
||||
while (j != NULL)
|
||||
{
|
||||
if (j->arg_num != -1 && (update_only || testing_only || consider_job(j)))
|
||||
{
|
||||
njobs++;
|
||||
obstack_grow(&tab_o, &j, sizeof(j));
|
||||
}
|
||||
j = j->next;
|
||||
}
|
||||
job_array = obstack_finish(&tab_o);
|
||||
|
||||
/* sort the jobs */
|
||||
qsort(job_array, (size_t)njobs, sizeof(*job_array),
|
||||
(int (*)(const void *, const void *))execution_order);
|
||||
}
|
424
anacron/runjob.c
Normal file
424
anacron/runjob.c
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
Anacron - run commands periodically
|
||||
Copyright (C) 1998 Itai Tzur <itzur@actcom.co.il>
|
||||
Copyright (C) 1999 Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "global.h"
|
||||
#include "cronie_common.h"
|
||||
|
||||
#include <langinfo.h>
|
||||
|
||||
static int
|
||||
temp_file(job_rec *jr)
|
||||
/* Open a temporary file and return its file descriptor */
|
||||
{
|
||||
char *dir;
|
||||
char template[PATH_MAX+1];
|
||||
int fdin = -1;
|
||||
int fdout;
|
||||
int len;
|
||||
|
||||
dir = getenv("TMPDIR");
|
||||
if (dir == NULL || *dir == '\0')
|
||||
dir = P_tmpdir;
|
||||
|
||||
len = snprintf(template, sizeof(template), "%s/$anacronXXXXXX", dir);
|
||||
if (len < 0)
|
||||
die_e("snprintf failed");
|
||||
else if ((size_t) len >= sizeof(template))
|
||||
die_e("TMPDIR too long");
|
||||
|
||||
fdout = mkstemp(template);
|
||||
if (fdout == -1) die_e("Can't open temporary file for writing");
|
||||
|
||||
fdin = open(template, O_RDONLY, S_IRUSR | S_IWUSR);
|
||||
if (fdin == -1) die_e("Can't open temporary file for reading");
|
||||
|
||||
if (unlink(template)) die_e("Can't unlink temporary file");
|
||||
|
||||
fcntl(fdout, F_SETFD, FD_CLOEXEC); /* set close-on-exec flag */
|
||||
fcntl(fdin, F_SETFD, FD_CLOEXEC); /* set close-on-exec flag */
|
||||
|
||||
jr->input_fd = fdin;
|
||||
jr->output_fd = fdout;
|
||||
|
||||
return fdout;
|
||||
}
|
||||
|
||||
static off_t
|
||||
file_size(int fd)
|
||||
/* Return the size of temporary file fd */
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st)) die_e("Can't fstat temporary file");
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
static char *
|
||||
username(void)
|
||||
{
|
||||
struct passwd *ps;
|
||||
static char *user;
|
||||
|
||||
if (user)
|
||||
return user;
|
||||
|
||||
ps = getpwuid(geteuid());
|
||||
if (ps == NULL || ps->pw_name == NULL) die_e("getpwuid() error");
|
||||
|
||||
user = strdup(ps->pw_name);
|
||||
if (user == NULL) die_e("memory allocation error");
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
static void
|
||||
xputenv(const char *s)
|
||||
{
|
||||
char *name = NULL, *val = NULL;
|
||||
char *eq_ptr;
|
||||
size_t eq_index;
|
||||
|
||||
if (s == NULL) {
|
||||
die_e("Invalid environment string");
|
||||
}
|
||||
|
||||
eq_ptr = strchr(s, '=');
|
||||
if (eq_ptr == NULL) {
|
||||
die_e("Invalid environment string");
|
||||
}
|
||||
|
||||
eq_index = (size_t) (eq_ptr - s);
|
||||
|
||||
name = malloc((eq_index + 1) * sizeof(char));
|
||||
if (name == NULL) {
|
||||
die_e("Not enough memory to set the environment");
|
||||
}
|
||||
|
||||
val = malloc((strlen(s) - eq_index) * sizeof(char));
|
||||
if (val == NULL) {
|
||||
die_e("Not enough memory to set the environment");
|
||||
}
|
||||
|
||||
strncpy(name, s, eq_index);
|
||||
name[eq_index] = '\0';
|
||||
strcpy(val, s + eq_index + 1);
|
||||
|
||||
if (setenv(name, val, 1)) {
|
||||
die_e("Can't set the environment");
|
||||
}
|
||||
|
||||
free(name);
|
||||
free(val);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
setup_env(const job_rec *jr)
|
||||
/* Setup the environment for the job according to /etc/anacrontab */
|
||||
{
|
||||
env_rec *er;
|
||||
|
||||
er = first_env_rec;
|
||||
if (er == NULL || jr->prev_env_rec == NULL) return;
|
||||
xputenv(er->assign);
|
||||
while (er != jr->prev_env_rec)
|
||||
{
|
||||
er = er->next;
|
||||
xputenv(er->assign);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
run_job(const job_rec *jr)
|
||||
/* This is called to start the job, after the fork */
|
||||
{
|
||||
/* setup stdout and stderr */
|
||||
xclose(1);
|
||||
xclose(2);
|
||||
if (dup2(jr->output_fd, 1) != 1 || dup2(jr->output_fd, 2) != 2)
|
||||
die_e("dup2() error"); /* dup2 also clears close-on-exec flag */
|
||||
in_background = 0; /* now, errors will be mailed to the user */
|
||||
if (chdir("/")) die_e("Can't chdir to '/'");
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &old_sigmask, NULL))
|
||||
die_e("sigprocmask error");
|
||||
xcloselog();
|
||||
execl("/bin/sh", "/bin/sh", "-c", jr->command, (char *)NULL);
|
||||
die_e("execl() error");
|
||||
}
|
||||
|
||||
static void
|
||||
xwrite(int fd, const char *string)
|
||||
/* Write (using write()) the string "string" to temporary file "fd".
|
||||
* Don't return on failure */
|
||||
{
|
||||
if (write(fd, string, strlen(string)) == -1)
|
||||
die_e("Can't write to temporary file");
|
||||
}
|
||||
|
||||
static int
|
||||
xwait(pid_t pid , int *status)
|
||||
/* Check if child process "pid" has finished. If it has, return 1 and its
|
||||
* exit status in "*status". If not, return 0.
|
||||
*/
|
||||
{
|
||||
pid_t r;
|
||||
|
||||
r = waitpid(pid, status, WNOHANG);
|
||||
if (r == -1) die_e("waitpid() error");
|
||||
if (r == 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
launch_mailer(job_rec *jr)
|
||||
{
|
||||
pid_t pid;
|
||||
struct stat buf;
|
||||
|
||||
if (jr->mailto == NULL)
|
||||
{
|
||||
explain("Empty MAILTO set, not mailing output");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check that we have a way of sending mail. */
|
||||
if(stat(SENDMAIL, &buf))
|
||||
{
|
||||
complain("Can't find sendmail at %s, not mailing output", SENDMAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
pid = xfork();
|
||||
if (pid == 0)
|
||||
{
|
||||
/* child */
|
||||
in_background = 1;
|
||||
/* set stdin to the job's output */
|
||||
xclose(STDIN_FILENO);
|
||||
if (dup2(jr->input_fd, STDIN_FILENO) != 0) die_e("Can't dup2()");
|
||||
if (lseek(STDIN_FILENO, 0, SEEK_SET) != 0) die_e("Can't lseek()");
|
||||
if (sigprocmask(SIG_SETMASK, &old_sigmask, NULL))
|
||||
die_e("sigprocmask error");
|
||||
xcloselog();
|
||||
|
||||
/* Ensure stdout/stderr are sane before exec-ing sendmail */
|
||||
/* coverity[leaked_handle] – STDOUT closed automatically */
|
||||
xclose(STDOUT_FILENO); xopen(STDOUT_FILENO, "/dev/null", O_WRONLY);
|
||||
/* coverity[leaked_handle] – STDERR closed automatically */
|
||||
xclose(STDERR_FILENO); xopen(STDERR_FILENO, "/dev/null", O_WRONLY);
|
||||
xclose(jr->output_fd);
|
||||
|
||||
/* Ensure stdin is not appendable ... ? */
|
||||
/* fdflags = fcntl(0, F_GETFL); fdflags &= ~O_APPEND; */
|
||||
/* fcntl(0, F_SETFL, fdflags ); */
|
||||
|
||||
/* Here, I basically mirrored the way /usr/sbin/sendmail is called
|
||||
* by cron on a Debian system, except for the "-oem" and "-or0s"
|
||||
* options, which don't seem to be appropriate here.
|
||||
* Hopefully, this will keep all the MTAs happy. */
|
||||
execl(SENDMAIL, SENDMAIL, "-FAnacron", "-odi",
|
||||
jr->mailto, (char *)NULL);
|
||||
die_e("Can't exec " SENDMAIL);
|
||||
}
|
||||
/* parent */
|
||||
/* record mailer pid */
|
||||
jr->mailer_pid = pid;
|
||||
running_mailers++;
|
||||
}
|
||||
|
||||
static void
|
||||
tend_mailer(job_rec *jr, int status)
|
||||
{
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||
complain("Tried to mail output of job `%s', "
|
||||
"but mailer process (" SENDMAIL ") exited with status %d",
|
||||
jr->ident, WEXITSTATUS(status));
|
||||
else if (!WIFEXITED(status) && WIFSIGNALED(status))
|
||||
complain("Tried to mail output of job `%s', "
|
||||
"but mailer process (" SENDMAIL ") got signal %d",
|
||||
jr->ident, WTERMSIG(status));
|
||||
else if (!WIFEXITED(status) && !WIFSIGNALED(status))
|
||||
complain("Tried to mail output of job `%s', "
|
||||
"but mailer process (" SENDMAIL ") terminated abnormally"
|
||||
, jr->ident);
|
||||
|
||||
jr->mailer_pid = 0;
|
||||
running_mailers--;
|
||||
}
|
||||
|
||||
void
|
||||
launch_job(job_rec *jr)
|
||||
{
|
||||
pid_t pid;
|
||||
int fd;
|
||||
char hostname[512];
|
||||
char *mailto;
|
||||
char *mailfrom;
|
||||
char mailto_expanded[MAX_EMAILSTR];
|
||||
char mailfrom_expanded[MAX_EMAILSTR];
|
||||
|
||||
/* get hostname */
|
||||
if (gethostname(hostname, 512)) {
|
||||
strcpy (hostname,"unknown machine");
|
||||
}
|
||||
|
||||
setup_env(jr);
|
||||
|
||||
/* Get the destination email address if set, or current user otherwise */
|
||||
mailto = getenv("MAILTO");
|
||||
if (mailto == NULL) {
|
||||
mailto = username();
|
||||
}
|
||||
else {
|
||||
if (expand_envvar(mailto, mailto_expanded, sizeof(mailto_expanded))) {
|
||||
mailto = mailto_expanded;
|
||||
}
|
||||
else {
|
||||
complain("The environment variable 'MAILTO' could not be expanded. The non-expanded value will be used.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the source email address if set, or current user otherwise */
|
||||
mailfrom = getenv("MAILFROM");
|
||||
if (mailfrom == NULL) {
|
||||
mailfrom = username();
|
||||
}
|
||||
else {
|
||||
if (expand_envvar(mailfrom, mailfrom_expanded, sizeof(mailfrom_expanded))) {
|
||||
mailfrom = mailfrom_expanded;
|
||||
}
|
||||
else {
|
||||
complain("The environment variable 'MAILFROM' could not be expanded. The non-expanded value will be used.");
|
||||
}
|
||||
}
|
||||
|
||||
/* create temporary file for stdout and stderr of the job */
|
||||
temp_file(jr); fd = jr->output_fd;
|
||||
/* write mail header */
|
||||
xwrite(fd, "From: ");
|
||||
xwrite(fd, "Anacron <");
|
||||
xwrite(fd, mailfrom);
|
||||
xwrite(fd, ">\n");
|
||||
xwrite(fd, "To: ");
|
||||
xwrite(fd, mailto);
|
||||
xwrite(fd, "\n");
|
||||
xwrite(fd, "MIME-Version: 1.0\n");
|
||||
xwrite(fd, "Content-Type: text/plain; charset=\"");
|
||||
xwrite(fd, nl_langinfo(CODESET));
|
||||
xwrite(fd, "\"\n");
|
||||
xwrite(fd, "Content-Transfer-Encoding: 8bit\n");
|
||||
xwrite(fd, "Subject: Anacron job '");
|
||||
xwrite(fd, jr->ident);
|
||||
xwrite(fd, "' on ");
|
||||
xwrite(fd, hostname);
|
||||
xwrite(fd, "\n\n");
|
||||
|
||||
if (*mailto == '\0')
|
||||
jr->mailto = NULL;
|
||||
else
|
||||
/* ugly but works without strdup() */
|
||||
jr->mailto = mailto;
|
||||
|
||||
jr->mail_header_size = file_size(fd);
|
||||
|
||||
pid = xfork();
|
||||
if (pid == 0)
|
||||
{
|
||||
/* child */
|
||||
in_background = 1;
|
||||
run_job(jr);
|
||||
/* execution never gets here */
|
||||
}
|
||||
/* parent */
|
||||
explain("Job `%s' started", jr->ident);
|
||||
jr->job_pid = pid;
|
||||
running_jobs++;
|
||||
}
|
||||
|
||||
static void
|
||||
tend_job(job_rec *jr, int status)
|
||||
/* Take care of a finished job */
|
||||
{
|
||||
int mail_output;
|
||||
const char *m;
|
||||
|
||||
update_timestamp(jr);
|
||||
unlock(jr);
|
||||
if (file_size(jr->output_fd) > jr->mail_header_size) mail_output = 1;
|
||||
else mail_output = 0;
|
||||
|
||||
m = mail_output ? " (produced output)" : "";
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||
explain("Job `%s' terminated%s", jr->ident, m);
|
||||
else if (WIFEXITED(status))
|
||||
explain("Job `%s' terminated (exit status: %d)%s",
|
||||
jr->ident, WEXITSTATUS(status), m);
|
||||
else if (WIFSIGNALED(status))
|
||||
complain("Job `%s' terminated due to signal %d%s",
|
||||
jr->ident, WTERMSIG(status), m);
|
||||
else /* is this possible? */
|
||||
complain("Job `%s' terminated abnormally%s", jr->ident, m);
|
||||
|
||||
jr->job_pid = 0;
|
||||
running_jobs--;
|
||||
if (mail_output) launch_mailer(jr);
|
||||
xclose(jr->output_fd);
|
||||
xclose(jr->input_fd);
|
||||
}
|
||||
|
||||
void
|
||||
tend_children(void)
|
||||
/* This is called whenever we get a SIGCHLD.
|
||||
* Takes care of zombie children.
|
||||
*/
|
||||
{
|
||||
int j;
|
||||
int status;
|
||||
|
||||
j = 0;
|
||||
while (j < njobs)
|
||||
{
|
||||
if (job_array[j]->mailer_pid != 0 &&
|
||||
xwait(job_array[j]->mailer_pid, &status))
|
||||
tend_mailer(job_array[j], status);
|
||||
if (job_array[j]->job_pid != 0 &&
|
||||
xwait(job_array[j]->job_pid, &status))
|
||||
tend_job(job_array[j], status);
|
||||
j++;
|
||||
}
|
||||
}
|
348
compile
Executable file
348
compile
Executable file
@ -0,0 +1,348 @@
|
||||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2018 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
|
||||
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
1476
config.guess
vendored
Executable file
1476
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
249
config.h.in
Normal file
249
config.h.in
Normal file
@ -0,0 +1,249 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* if you have a tm_gmtoff member in struct tm */
|
||||
#undef CAPITALIZE_FOR_PS
|
||||
|
||||
/* Code will be built with debug info. */
|
||||
#undef DEBUGGING
|
||||
|
||||
/* default editor */
|
||||
#undef EDITOR
|
||||
|
||||
/* Define if you want system crontab. */
|
||||
#undef ENABLE_SYSCRONTAB
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the `fchgrp' function. */
|
||||
#undef HAVE_FCHGRP
|
||||
|
||||
/* Define to 1 if you have the `fchown' function. */
|
||||
#undef HAVE_FCHOWN
|
||||
|
||||
/* Define to 1 if you have the `fcntl' function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `flock' function. */
|
||||
#undef HAVE_FLOCK
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define to 1 if you have the `getseuserbyname' function. */
|
||||
#undef HAVE_GETSEUSERBYNAME
|
||||
|
||||
/* Define to 1 if you have the `get_default_context_with_level' function. */
|
||||
#undef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#undef HAVE_GLOB_H
|
||||
|
||||
/* Define to 1 if you have the `inotify_add_watch' function. */
|
||||
#undef HAVE_INOTIFY_ADD_WATCH
|
||||
|
||||
/* Define to 1 if you have the `inotify_init' function. */
|
||||
#undef HAVE_INOTIFY_INIT
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `pam' library (-lpam). */
|
||||
#undef HAVE_LIBPAM
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the `lockf' function. */
|
||||
#undef HAVE_LOCKF
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `pam_getenvlist' function. */
|
||||
#undef HAVE_PAM_GETENVLIST
|
||||
|
||||
/* Define to 1 if you have the <pam/pam_appl.h> header file. */
|
||||
#undef HAVE_PAM_PAM_APPL_H
|
||||
|
||||
/* Define to 1 if you have the `pam_putenv' function. */
|
||||
#undef HAVE_PAM_PUTENV
|
||||
|
||||
/* Define to 1 if you have the <paths.h> header file. */
|
||||
#undef HAVE_PATHS_H
|
||||
|
||||
/* Define to 1 if you have the <pty.h> header file. */
|
||||
#undef HAVE_PTY_H
|
||||
|
||||
/* Define to 1 if you have the <security/pam_appl.h> header file. */
|
||||
#undef HAVE_SECURITY_PAM_APPL_H
|
||||
|
||||
/* Define to 1 if you have the <selinux/selinux.h> header file. */
|
||||
#undef HAVE_SELINUX_SELINUX_H
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
|
||||
#undef HAVE_STRUCT_TM_TM_GMTOFF
|
||||
|
||||
/* Define to 1 if you have the <sys/audit.h> header file. */
|
||||
#undef HAVE_SYS_AUDIT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||
#undef HAVE_SYS_CDEFS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/inotify.h> header file. */
|
||||
#undef HAVE_SYS_INOTIFY_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stream.h> header file. */
|
||||
#undef HAVE_SYS_STREAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stropts.h> header file. */
|
||||
#undef HAVE_SYS_STROPTS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/timers.h> header file. */
|
||||
#undef HAVE_SYS_TIMERS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <util.h> header file. */
|
||||
#undef HAVE_UTIL_H
|
||||
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#undef HAVE_UTIME_H
|
||||
|
||||
/* There will be path to sendmail. */
|
||||
#undef MAILARG
|
||||
|
||||
/* -i = don't terminate on "." by itself -Fx = Set full-name of sender -odi =
|
||||
Option Deliverymode Interactive -oem = Option Errors Mailedtosender -oi =
|
||||
Ignore "." alone on a line -t = Get recipient from headers -f %s = Envelope
|
||||
sender address -d = undocumented but common flag. */
|
||||
#undef MAILFMT
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Using syslog for log messages. */
|
||||
#undef SYSLOG
|
||||
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define if you want Audit trails. */
|
||||
#undef WITH_AUDIT
|
||||
|
||||
/* Define if you want inotify support. */
|
||||
#undef WITH_INOTIFY
|
||||
|
||||
/* Define if you want to enable PAM support */
|
||||
#undef WITH_PAM
|
||||
|
||||
/* Define if you want SELinux support. */
|
||||
#undef WITH_SELINUX
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef mode_t
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
1833
config.sub
vendored
Executable file
1833
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
273
configure.ac
Normal file
273
configure.ac
Normal file
@ -0,0 +1,273 @@
|
||||
AC_INIT([cronie],[1.6.1])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREREQ([2.64])
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
|
||||
[AC_SUBST([AM_DEFAULT_VERBOSITY], [1])])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
dnl Checks for programs.
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
|
||||
dnl Check for _GNU_SOURCE
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
AC_CHECK_HEADERS( \
|
||||
dirent.h \
|
||||
fcntl.h \
|
||||
getopt.h \
|
||||
glob.h \
|
||||
limits.h \
|
||||
paths.h \
|
||||
pty.h \
|
||||
selinux/selinux.h \
|
||||
stddef.h \
|
||||
stdint.h \
|
||||
sys/audit.h \
|
||||
sys/inotify.h \
|
||||
sys/stat.h \
|
||||
sys/stream.h \
|
||||
sys/stropts.h \
|
||||
sys/time.h \
|
||||
sys/timers.h \
|
||||
sys/types.h \
|
||||
sys/cdefs.h \
|
||||
time.h \
|
||||
unistd.h \
|
||||
util.h \
|
||||
utime.h \
|
||||
)
|
||||
|
||||
AC_CHECK_FUNCS( \
|
||||
fcntl \
|
||||
lockf \
|
||||
flock \
|
||||
fchown \
|
||||
fchgrp \
|
||||
)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_TM
|
||||
AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[#include <time.h>])
|
||||
|
||||
dnl Checking for programs
|
||||
|
||||
AC_ARG_WITH([editor],
|
||||
[AS_HELP_STRING([--with-editor=EDITOR],[path to default editor])],
|
||||
[editor_defined="$with_editor"],
|
||||
[editor_defined="no"])
|
||||
AS_IF([test "x$editor_defined" = "xno"], [
|
||||
AC_PATH_PROG([editor_defined], [vi], [/usr/bin/vi])
|
||||
])
|
||||
AC_DEFINE_UNQUOTED([EDITOR], ["$editor_defined"], [default editor])
|
||||
|
||||
AC_MSG_CHECKING(username to run under)
|
||||
AC_ARG_WITH(daemon_username,
|
||||
[AS_HELP_STRING([--with-daemon_username=DAEMON_USERNAME], [Username to run under (default daemon) ])],
|
||||
[ case "$withval" in
|
||||
no)
|
||||
AC_MSG_ERROR(Need DAEMON_USERNAME.)
|
||||
;;
|
||||
yes)
|
||||
DAEMON_USERNAME=daemon
|
||||
AC_MSG_RESULT(daemon)
|
||||
;;
|
||||
*)
|
||||
DAEMON_USERNAME="$withval";
|
||||
AC_MSG_RESULT($withval)
|
||||
;;
|
||||
esac ],
|
||||
DAEMON_USERNAME=daemon
|
||||
AC_MSG_RESULT(daemon)
|
||||
)
|
||||
AC_SUBST(DAEMON_USERNAME)
|
||||
|
||||
AC_MSG_CHECKING(groupname to run under)
|
||||
AC_ARG_WITH(daemon_groupname,
|
||||
[AS_HELP_STRING([--with-daemon_groupname=DAEMON_GROUPNAME], [Groupname to run under (default daemon) ])],
|
||||
[ case "$withval" in
|
||||
no)
|
||||
AC_MSG_ERROR(Need DAEMON_GROUPNAME.)
|
||||
;;
|
||||
yes)
|
||||
DAEMON_GROUPNAME=daemon
|
||||
AC_MSG_RESULT(daemon)
|
||||
;;
|
||||
*)
|
||||
DAEMON_GROUPNAME="$withval";
|
||||
AC_MSG_RESULT($withval)
|
||||
;;
|
||||
esac ],
|
||||
DAEMON_GROUPNAME=daemon
|
||||
AC_MSG_RESULT(daemon)
|
||||
)
|
||||
AC_SUBST(DAEMON_GROUPNAME)
|
||||
|
||||
# Check whether inotify is accepted
|
||||
AC_ARG_WITH(inotify,
|
||||
[AS_HELP_STRING([--with-inotify], [ Enable inotify support])],
|
||||
[ if test "x$withval" != "xno" ; then
|
||||
AC_DEFINE(WITH_INOTIFY,1,[Define if you want inotify support.])
|
||||
AC_CHECK_HEADER([sys/inotify.h], , AC_MSG_ERROR(Inotify support requires sys/inotify.h header))
|
||||
AC_CHECK_FUNCS(inotify_init inotify_add_watch)
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(pie,CRONIE_HELP_STRING(--enable-pie,Build cronie as a Position Independent Executable))
|
||||
if test "x$enable_pie" = xyes; then
|
||||
CFLAGS="$CFLAGS -fPIE -DPIE"
|
||||
LDFLAGS="$LDFLAGS -pie"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(relro,CRONIE_HELP_STRING(--enable-relro,Build cronie with relro flag))
|
||||
if test "x$enable_relro" = xyes; then
|
||||
LDFLAGS="$LDFLAGS -Wl,-z,relro -Wl,-z,now"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(bsd, BSD_STRING(--enable-bsd,Build cronie with BSD specific parts))
|
||||
|
||||
# Check whether user wants SELinux support
|
||||
SELINUX_MSG="no"
|
||||
LIBSELINUX=""
|
||||
AC_ARG_WITH(selinux,
|
||||
[AS_HELP_STRING([--with-selinux], [Enable SELinux support])],
|
||||
[ if test "x$withval" != "xno" ; then
|
||||
saved_LIBS="$LIBS"
|
||||
AC_DEFINE(WITH_SELINUX,1,[Define if you want SELinux support.])
|
||||
SELINUX_MSG="yes"
|
||||
AC_CHECK_HEADER([selinux/selinux.h], ,AC_MSG_ERROR(SELinux support requires selinux.h header))
|
||||
AC_CHECK_LIB(selinux, setexeccon, [ LIBSELINUX="-lselinux" ],
|
||||
AC_MSG_ERROR(SELinux support requires libselinux library))
|
||||
AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level)
|
||||
LIBS="$saved_LIBS"
|
||||
AC_SUBST(LIBSELINUX)
|
||||
fi ]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(pam, [AS_HELP_STRING([--with-pam], [Build with PAM support])])
|
||||
AC_ARG_ENABLE(pam, [AS_HELP_STRING([--enable-pam], [Alias for --with-pam])])
|
||||
|
||||
# Check that with_pam and enable_pam are consistent.
|
||||
# If neither one is set, the default is "no."
|
||||
if test -z "$with_pam"; then
|
||||
with_pam=${enable_pam:-no}
|
||||
elif test -n "$enable_pam" && test "$with_pam" != "$enable_pam"; then
|
||||
AC_MSG_ERROR(
|
||||
[Contradicting --with/without-pam and --enable/disable-pam options.])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([PAM], [test "$with_pam" != no])
|
||||
|
||||
if test "$with_pam" != no; then
|
||||
AC_DEFINE(WITH_PAM, 1, [Define if you want to enable PAM support])
|
||||
pam_appl_h_found=no
|
||||
AC_CHECK_HEADERS([pam/pam_appl.h security/pam_appl.h],
|
||||
[pam_appl_h_found=yes])
|
||||
test "$pam_appl_h_found" = yes ||
|
||||
AC_MSG_ERROR([PAM headers not found])
|
||||
|
||||
saved_LIBS="$LIBS"
|
||||
AC_CHECK_LIB([dl], [dlopen], [libdl_found=yes], [libdl_found=no])
|
||||
AC_CHECK_LIB(pam, pam_set_item, , AC_MSG_ERROR([*** libpam missing]))
|
||||
AC_CHECK_FUNCS([pam_getenvlist pam_putenv])
|
||||
LIBS="$saved_LIBS"
|
||||
|
||||
case $libdl_found:" $LIBS " in #(
|
||||
*" -ldl "*) LIBPAM= ;; #(
|
||||
yes:*) LIBPAM=-ldl ;; # libdl found, but is not in $LIBS
|
||||
esac
|
||||
AC_SUBST([LIBPAM], ["-lpam $LIBPAM"])
|
||||
fi
|
||||
|
||||
AC_DEFINE(DEBUGGING,1,[Code will be built with debug info.])
|
||||
|
||||
AC_DEFINE(MAILARG,"/usr/sbin/sendmail",[There will be path to sendmail.])
|
||||
|
||||
AC_DEFINE(MAILFMT,"%s -FCronDaemon -i -odi -oem -oi -t -f %s",
|
||||
[-i = don't terminate on "." by itself
|
||||
-Fx = Set full-name of sender
|
||||
-odi = Option Deliverymode Interactive
|
||||
-oem = Option Errors Mailedtosender
|
||||
-oi = Ignore "." alone on a line
|
||||
-t = Get recipient from headers
|
||||
-f %s = Envelope sender address
|
||||
-d = undocumented but common flag.])
|
||||
|
||||
AC_DEFINE(SYSLOG,1,[Using syslog for log messages.])
|
||||
|
||||
AC_DEFINE(CAPITALIZE_FOR_PS, 1, [if you have a tm_gmtoff member in struct tm])
|
||||
|
||||
# Check whether user wants Linux audit support
|
||||
AC_ARG_WITH(audit,
|
||||
[AS_HELP_STRING([--with-audit], [Enable audit trails])],
|
||||
[ if test "x$withval" != "xno" ; then
|
||||
saved_LIBS="$LIBS"
|
||||
AC_DEFINE(WITH_AUDIT,1,[Define if you want Audit trails.])
|
||||
AC_CHECK_HEADER([libaudit.h], ,AC_MSG_ERROR(Audit trails requires libaudit.h header))
|
||||
AC_CHECK_LIB(audit, audit_open, [ LIBAUDIT="-laudit" ],
|
||||
AC_MSG_ERROR(Audit support needs audit libraries.))
|
||||
LIBS="$saved_LIBS"
|
||||
AC_SUBST(LIBAUDIT)
|
||||
fi ]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(syscrontab,
|
||||
[AS_HELP_STRING([--enable-syscrontab], [Build cronie with system crontab enabled.])],
|
||||
[ if test "x$enableval" != xno; then
|
||||
AC_DEFINE(ENABLE_SYSCRONTAB,1,[Define if you want system crontab.])
|
||||
fi ], [AC_DEFINE(ENABLE_SYSCRONTAB,1,[Define if you want system crontab.])]
|
||||
)
|
||||
|
||||
dnl CRONIE_VAR_DEFAULT (VAR, DESCRIPTION, DEFAULT)
|
||||
dnl --------------------------------------------
|
||||
AC_DEFUN([CRONIE_CONF_VAR],
|
||||
[AC_ARG_VAR([$1], [$2 @<:@$3@:>@])
|
||||
if test "$$1" = ""; then
|
||||
$1='$3'
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([ANACRON_CONF_VAR],
|
||||
[AC_ARG_VAR([$1], [$2 @<:@$3@:>@])
|
||||
if test "$$1" = ""; then
|
||||
$1='$3'
|
||||
fi
|
||||
])
|
||||
|
||||
CRONIE_CONF_VAR([SYSCRONTAB], [the current working directory of the running daemon], [${sysconfdir}/crontab])
|
||||
CRONIE_CONF_VAR([SYS_CROND_DIR], [the current working directory of the running daemon], [${sysconfdir}/cron.d])
|
||||
CRONIE_CONF_VAR([SPOOL_DIR], [the directory where all the user cron tabs reside], [${localstatedir}/spool/cron])
|
||||
|
||||
AC_ARG_ENABLE([anacron], [AS_HELP_STRING([--disable-anacron], [Do not build anacron.])], [], [enable_anacron=yes])
|
||||
AM_CONDITIONAL([ANACRON], [test "$enable_anacron" = yes])
|
||||
if test "$enable_anacron" != no; then
|
||||
ANACRON_CONF_VAR([ANACRON_SPOOL_DIR],[The path for anacron locks.],[${localstatedir}/spool/anacron])
|
||||
ANACRON_CONF_VAR([ANACRONTAB],[The anacron table for regular jobs.],[${sysconfdir}/anacrontab])
|
||||
|
||||
dnl obstack.h is part of GLIBC and may not be present on other systems,
|
||||
dnl eg. musl and AIX. There, we static link in our own copy.
|
||||
AC_CHECK_HEADER(obstack.h, [have_obstack=yes], [have_obstack=no], [])
|
||||
fi
|
||||
AM_CONDITIONAL([NEED_OBSTACK], [test "$have_obstack" = no])
|
||||
AS_IF([test "$enable_anacron" != no && test "$have_obstack" = no], [
|
||||
CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/obstack"
|
||||
])
|
||||
|
||||
AM_CONDITIONAL(HAS_RUNSTATE, [test x$runstatedir != x])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
25
contrib/0anacron
Normal file
25
contrib/0anacron
Normal file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# Check whether 0anacron was run today already
|
||||
if test -r /var/spool/anacron/cron.daily; then
|
||||
day=`cat /var/spool/anacron/cron.daily`
|
||||
fi
|
||||
if [ `date +%Y%m%d` = "$day" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do not run jobs when on battery power
|
||||
online=1
|
||||
for psupply in /sys/class/power_supply/* ; do
|
||||
if [ `cat "$psupply/type" 2>/dev/null`x = Mainsx ] && [ -f "$psupply/online" ]; then
|
||||
if [ `cat "$psupply/online" 2>/dev/null`x = 1x ]; then
|
||||
online=1
|
||||
break
|
||||
else
|
||||
online=0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ $online = 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
/usr/sbin/anacron -s
|
5
contrib/0hourly
Normal file
5
contrib/0hourly
Normal file
@ -0,0 +1,5 @@
|
||||
# Run the hourly jobs
|
||||
SHELL=/bin/bash
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
MAILTO=root
|
||||
01 * * * * root run-parts /etc/cron.hourly
|
16
contrib/anacrontab
Normal file
16
contrib/anacrontab
Normal file
@ -0,0 +1,16 @@
|
||||
# /etc/anacrontab: configuration file for anacron
|
||||
|
||||
# See anacron(8) and anacrontab(5) for details.
|
||||
|
||||
SHELL=/bin/sh
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
MAILTO=root
|
||||
# the maximal random delay added to the base delay of the jobs
|
||||
RANDOM_DELAY=45
|
||||
# the jobs will be started during the following hours only
|
||||
START_HOURS_RANGE=3-22
|
||||
|
||||
#period in days delay in minutes job-identifier command
|
||||
1 5 cron.daily nice run-parts /etc/cron.daily
|
||||
7 25 cron.weekly nice run-parts /etc/cron.weekly
|
||||
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
|
15
contrib/cronie.systemd
Normal file
15
contrib/cronie.systemd
Normal file
@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Command Scheduler
|
||||
After=auditd.service nss-user-lookup.target systemd-user-sessions.service time-sync.target ypbind.service autofs.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/etc/sysconfig/crond
|
||||
ExecStart=/usr/sbin/crond -n $CRONDARGS
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
RestartSec=30s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
9
contrib/dailyjobs
Normal file
9
contrib/dailyjobs
Normal file
@ -0,0 +1,9 @@
|
||||
# Run the daily, weekly, and monthly jobs if cronie-anacron is not installed
|
||||
SHELL=/bin/bash
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
MAILTO=root
|
||||
|
||||
# run-parts
|
||||
02 4 * * * root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.daily
|
||||
22 4 * * 0 root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.weekly
|
||||
42 4 1 * * root [ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.monthly
|
3
crond.sysconfig
Normal file
3
crond.sysconfig
Normal file
@ -0,0 +1,3 @@
|
||||
# Settings for the CRON daemon.
|
||||
# CRONDARGS= : any extra command-line startup arguments for crond
|
||||
CRONDARGS=
|
132
cronie.init
Executable file
132
cronie.init
Executable file
@ -0,0 +1,132 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# crond Start/Stop the cron clock daemon.
|
||||
#
|
||||
# chkconfig: 2345 90 60
|
||||
# description: cron is a standard UNIX program that runs user-specified \
|
||||
# programs at periodic scheduled times. vixie cron adds a \
|
||||
# number of features to the basic UNIX cron, including better \
|
||||
# security and more powerful configuration options.
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: crond crontab
|
||||
# Required-Start: $local_fs $syslog
|
||||
# Required-Stop: $local_fs $syslog
|
||||
# Default-Start: 2345
|
||||
# Default-Stop: 90
|
||||
# Short-Description: run cron daemon
|
||||
# Description: cron is a standard UNIX program that runs user-specified
|
||||
# programs at periodic scheduled times. vixie cron adds a
|
||||
# number of features to the basic UNIX cron, including better
|
||||
# security and more powerful configuration options.
|
||||
### END INIT INFO
|
||||
|
||||
[ -f /etc/sysconfig/crond ] || {
|
||||
[ "$1" = "status" ] && exit 4 || exit 6
|
||||
}
|
||||
|
||||
RETVAL=0
|
||||
prog="crond"
|
||||
exec=/usr/sbin/crond
|
||||
lockfile=/var/lock/subsys/crond
|
||||
config=/etc/sysconfig/crond
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
[ $UID -eq 0 ] && [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
|
||||
|
||||
start() {
|
||||
if [ $(id -ru) -ne 0 ] ; then
|
||||
echo "User has insufficient privilege."
|
||||
exit 4
|
||||
fi
|
||||
[ -x $exec ] || exit 5
|
||||
[ -f $config ] || exit 6
|
||||
printf "Starting $prog: "
|
||||
daemon $prog $CRONDARGS
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && touch $lockfile
|
||||
}
|
||||
|
||||
stop() {
|
||||
if [ $(id -ru) -ne 0 ] ; then
|
||||
echo "User has insufficient privilege."
|
||||
exit 4
|
||||
fi
|
||||
printf "Stopping $prog: "
|
||||
if [ -n "`pidfileofproc $exec`" ]; then
|
||||
killproc $exec
|
||||
RETVAL=3
|
||||
else
|
||||
failure "Stopping $prog"
|
||||
fi
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && rm -f $lockfile
|
||||
}
|
||||
|
||||
restart() {
|
||||
rh_status_q && stop
|
||||
start
|
||||
}
|
||||
|
||||
reload() {
|
||||
printf "Reloading $prog: "
|
||||
if [ -n "`pidfileofproc $exec`" ]; then
|
||||
killproc $exec -HUP
|
||||
else
|
||||
failure "Reloading $prog"
|
||||
fi
|
||||
retval=$?
|
||||
echo
|
||||
}
|
||||
|
||||
force_reload() {
|
||||
# new configuration takes effect after restart
|
||||
restart
|
||||
}
|
||||
|
||||
rh_status() {
|
||||
# run checks to determine if the service is running or use generic status
|
||||
status -p /var/run/crond.pid $prog
|
||||
}
|
||||
|
||||
rh_status_q() {
|
||||
rh_status >/dev/null 2>&1
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
rh_status_q && exit 0
|
||||
$1
|
||||
;;
|
||||
stop)
|
||||
rh_status_q || exit 0
|
||||
$1
|
||||
;;
|
||||
restart)
|
||||
$1
|
||||
;;
|
||||
reload)
|
||||
rh_status_q || exit 7
|
||||
$1
|
||||
;;
|
||||
force-reload)
|
||||
force_reload
|
||||
;;
|
||||
status)
|
||||
rh_status
|
||||
;;
|
||||
condrestart|try-restart)
|
||||
rh_status_q || exit 0
|
||||
restart
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
|
||||
exit 2
|
||||
esac
|
||||
exit $?
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
a675051e62a715afb3efa87d50813f879c43955b
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
021dcc67fe5ba149c31aa82085a05c37f080e7b9
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
c3ce1e892ef195c372aacde1d4bff06d1007c657
|
137
cronie_common.c
Normal file
137
cronie_common.c
Normal file
@ -0,0 +1,137 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Return:
|
||||
* 0 - Not found
|
||||
* 1 - Found */
|
||||
static int find_envvar(const char *source, const char **start_pos, size_t *length) {
|
||||
const char *reader;
|
||||
size_t size = 1;
|
||||
int waiting_close = 0;
|
||||
|
||||
*length = 0;
|
||||
*start_pos = NULL;
|
||||
|
||||
if (source == NULL || *source == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start_pos = strchr(source, '$');
|
||||
|
||||
if (*start_pos == NULL) {
|
||||
return 0;
|
||||
}
|
||||
/* Skip $, since all envvars start with this char */
|
||||
reader = *start_pos + 1;
|
||||
|
||||
while (*reader != '\0') {
|
||||
if (*reader == '_' || isalnum(*reader)) {
|
||||
if (size <= 2 && isdigit(*reader)) {
|
||||
goto not_found;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
else if (*reader == '{') {
|
||||
if (size != 1) {
|
||||
goto not_found;
|
||||
}
|
||||
size++;
|
||||
waiting_close = 1;
|
||||
}
|
||||
else if (*reader == '}') {
|
||||
if ((waiting_close && size == 2) || size == 1) {
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
if (waiting_close) {
|
||||
size++;
|
||||
}
|
||||
|
||||
waiting_close = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
reader++;
|
||||
}
|
||||
|
||||
if (waiting_close) {
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
*length = size;
|
||||
return 1;
|
||||
|
||||
not_found:
|
||||
*length = 0;
|
||||
*start_pos = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expand env variables in 'source' arg and save to 'result'
|
||||
* Return:
|
||||
* 1 - Success
|
||||
* 0 - Fail */
|
||||
int expand_envvar(const char *source, char *result, size_t max_size) {
|
||||
const char *envvar_p;
|
||||
size_t envvar_name_size = 0;
|
||||
|
||||
*result = '\0';
|
||||
|
||||
while (find_envvar(source, &envvar_p, &envvar_name_size)) {
|
||||
char *envvar_name, *envvar_value;
|
||||
size_t prefix_size;
|
||||
|
||||
/* Copy content before env var name */
|
||||
prefix_size = envvar_p - source;
|
||||
|
||||
if (prefix_size > 0) {
|
||||
if ((strlen(result) + prefix_size + 1) > max_size) {
|
||||
goto too_big;
|
||||
}
|
||||
strncat(result, source, prefix_size);
|
||||
}
|
||||
|
||||
/* skip envvar name */
|
||||
source = envvar_p + envvar_name_size;
|
||||
|
||||
/* copy envvar name, ignoring $, { and } chars*/
|
||||
envvar_p++;
|
||||
envvar_name_size--;
|
||||
|
||||
if (*envvar_p == '{') {
|
||||
envvar_p++;
|
||||
envvar_name_size = envvar_name_size - 2;
|
||||
}
|
||||
|
||||
envvar_name = malloc(envvar_name_size + 1);
|
||||
strncpy(envvar_name, envvar_p, envvar_name_size);
|
||||
envvar_name[envvar_name_size] = '\0';
|
||||
|
||||
/* Copy envvar value to result */
|
||||
envvar_value = getenv(envvar_name);
|
||||
free(envvar_name);
|
||||
|
||||
if (envvar_value != NULL) {
|
||||
if ((strlen(result) + strlen(envvar_value) + 1) > max_size) {
|
||||
goto too_big;
|
||||
}
|
||||
strcat(result, envvar_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy any character left in the source string */
|
||||
if (*source != '\0') {
|
||||
if ((strlen(result) + strlen(source) + 1) > max_size) {
|
||||
goto too_big;
|
||||
}
|
||||
strcat(result, source);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
too_big:
|
||||
return 0;
|
||||
}
|
43
cronie_common.h
Normal file
43
cronie_common.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Copyright Red Hat Software
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Collection of definitions, inline functions, etc, that are useful for
|
||||
* both cron and anacron. */
|
||||
|
||||
#ifndef CRONIE_COMMON_H
|
||||
#define CRONIE_COMMON_H
|
||||
|
||||
#ifndef __attribute__
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
|
||||
# define __attribute__(x) /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_NORETURN
|
||||
# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#ifndef MAX_EMAILSTR
|
||||
#define MAX_EMAILSTR 255 /* max length of email address strings (254 + \0) */
|
||||
#endif
|
||||
|
||||
int expand_envvar(const char *, char *, size_t);
|
||||
|
||||
#endif /* CRONIE_COMMON_H */
|
16
debian/README.Debian
vendored
Normal file
16
debian/README.Debian
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
cronie for Debian
|
||||
-----------------
|
||||
|
||||
This version of cronie has been patched and configured to be as compatible as
|
||||
possible to Debian's standard job scheduler, ISC cron. You should be able to
|
||||
switch between these implementations without experiencing any major negative
|
||||
side effects to your system.
|
||||
|
||||
Feature-wise, however, there still are quite a number of subtle and
|
||||
not-so-subtle differences (mostly because of how much Debian's version of ISC
|
||||
cron is patched), so be sure to read the manpages.
|
||||
|
||||
cronie installs a file /etc/cron.deny (empty), thereby enabling all users to
|
||||
use the crontab(1) command by default.
|
||||
|
||||
-- Christian Kastner <ckk@debian.org> Sun, 20 Mar 2011 01:27:55 +0100
|
134
debian/changelog
vendored
Normal file
134
debian/changelog
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
cronie (1.6.1-5) experimental; urgency=medium
|
||||
|
||||
* cronie pre-depends now on cron-daemon-common, and does no longer install
|
||||
conflicting files.
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Sun, 13 Nov 2022 17:09:31 +0100
|
||||
|
||||
cronie (1.6.1-4) experimental; urgency=medium
|
||||
|
||||
* fixed the watch file
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Tue, 01 Nov 2022 21:53:41 +0100
|
||||
|
||||
cronie (1.6.1-3) experimental; urgency=medium
|
||||
|
||||
* reverted previous changes, as I did not notice the closed ITA bug
|
||||
#974038, came back to contents authored by Lin Lance.
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Thu, 12 May 2022 10:35:36 +0200
|
||||
|
||||
cronie (1.6.1-2) experimental; urgency=medium
|
||||
|
||||
* refreshed debian patches, which were targetted to version 1.5.5
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Tue, 10 May 2022 17:56:24 +0200
|
||||
|
||||
cronie (1.6.1-1) experimental; urgency=medium
|
||||
|
||||
* New upstream version (1.6.1)
|
||||
* Refreshed patches
|
||||
* d/control: New maintainer (Closes: #974038)
|
||||
* d/control: Updated standards (4.6.0), dh-compat (13)
|
||||
|
||||
-- Lance Lin <LQi254@protonmail.com> Tue, 03 May 2022 21:21:59 +0700
|
||||
|
||||
cronie (1.5.5-3) experimental; urgency=medium
|
||||
|
||||
* Add Hurd-workaround-for-PATH_MAX.patch (Closes: #638048)
|
||||
* Fix spelling error in previous changelog entry
|
||||
|
||||
-- Christian Kastner <ckk@debian.org> Tue, 05 Nov 2019 08:04:37 +0100
|
||||
|
||||
cronie (1.5.5-2) experimental; urgency=medium
|
||||
|
||||
* Don't build /usr/sbin/anacron
|
||||
/usr/sbin/anacron is still provided by src:anacron.
|
||||
Thanks, Andreas Beckmann, for catching this! (Closes: #944024)
|
||||
|
||||
-- Christian Kastner <ckk@debian.org> Sun, 03 Nov 2019 11:12:33 +0100
|
||||
|
||||
cronie (1.5.5-1) experimental; urgency=medium
|
||||
|
||||
* New upstream version 1.5.5
|
||||
* Drop patches (included upstream):
|
||||
- crond-report-missing-newline-before-EOF.patch
|
||||
- crontab-Add-Y-N-to-retry-prompt.patch
|
||||
- crontab-fsync-to-check-for-full-disk.patch
|
||||
- crontab.1-Various-fixes-and-improvements.patch
|
||||
- entries-Explicitly-validate-upper-ranges-and-steps.patch
|
||||
* Refresh patches
|
||||
- debian/patches/Manpage-and-typo-fixes.patch
|
||||
- debian/patches/Rename-PAM-service-to-cronie.patch
|
||||
+ Split out Unbundle-upstream-PAM-config.patch from this one
|
||||
|
||||
-- Christian Kastner <ckk@debian.org> Thu, 31 Oct 2019 22:20:05 +0100
|
||||
|
||||
cronie (1.5.4-final-2) experimental; urgency=medium
|
||||
|
||||
* build: Set default EDITOR to /usr/bin/sensible-editor
|
||||
* d/patches (added):
|
||||
- crond-report-missing-newline-before-EOF.patch
|
||||
- entries-Explicitly-validate-upper-ranges-and-steps.patch
|
||||
- crontab.1-Various-fixes-and-improvements.patch
|
||||
- crontab-Add-Y-N-to-retry-prompt.patch
|
||||
- crontab-fsync-to-check-for-full-disk.patch
|
||||
|
||||
-- Christian Kastner <ckk@debian.org> Wed, 30 Oct 2019 21:12:01 +0100
|
||||
|
||||
cronie (1.5.4-final-1) experimental; urgency=medium
|
||||
|
||||
* New upstream release. (Closes: #697811, #783856)
|
||||
|
||||
[ Andreas Henriksson ]
|
||||
* debian/watch: update for cronie move to github
|
||||
* Modify patches to apply against new upstream release
|
||||
* Add debian/gbp.conf
|
||||
* Adjust and ship the cronie.service file
|
||||
* Use debian/clean to remove src/cron-paths.h
|
||||
* Fix lintian warning about not using default-mta
|
||||
* Fix typo in patch tagging meta-header
|
||||
|
||||
[ Christian Kastner ]
|
||||
* d/control:
|
||||
- Switch Build-Depends from debhelper to debhelper-compat
|
||||
- Bump debhelper compatibility level to 12
|
||||
- Bump Standards-Version to 4.4.1 (no changes needed)
|
||||
- Remove now obsolete d/compat file
|
||||
- Set Rules-Requires-Root: no
|
||||
We don't need (fake)root for building the package.
|
||||
- Point Homepage to GitHub
|
||||
- Set Vcs-* URLs for Salsa
|
||||
- Mark package cronie as Multi-Arch: foreign
|
||||
- Add Pre-Depends: ${misc:Pre-Depends} to binary package
|
||||
As recommended by lintian's skip-systemd-native-flag-missing-pre-depends
|
||||
* d/cronie.default: Add new daemon flag "-P"
|
||||
* d/rules:
|
||||
- Add hardening flags
|
||||
- Stop passing actions to dh_installinit
|
||||
This has been obsoleted by dependency-based booting in Wheezy, see
|
||||
https://lists.debian.org/debian-devel/2013/05/msg01109.html
|
||||
- Use DEB_HOST_ARCH_OS from /usr/share/dpkg/architecture.mk
|
||||
- Proper passing of CFLAGS through DEB_CFLAGS_MAINT_APPEND
|
||||
* d/copyright:
|
||||
- Fix syntax errors
|
||||
- Switch URL to official policy URL
|
||||
- Point Source to GitHub
|
||||
fedorahosted.org has been retired
|
||||
- Bump copyrights
|
||||
* d/clean: Remove generated files for (non-enabled) anacron build
|
||||
* Sync maintscripts with src:cron
|
||||
|
||||
-- Christian Kastner <ckk@debian.org> Mon, 28 Oct 2019 19:35:38 +0100
|
||||
|
||||
cronie (1.4.8-1~exp1) experimental; urgency=low
|
||||
|
||||
* Initial release (Closes: #590876)
|
||||
* debian/patches added:
|
||||
- 0001-Unbundle-anacron
|
||||
- 0002-Manpage-and-typo-fixes
|
||||
- 0003-Rename-PAM-service-to-cronie
|
||||
- 0004-Debian-specific-paths-and-features
|
||||
- 0005-Extend-support-for-kFreeBSD-and-GNU-HURD
|
||||
|
||||
-- Christian Kastner <debian@kvr.at> Tue, 26 Jul 2011 14:00:34 +0200
|
2
debian/clean
vendored
Normal file
2
debian/clean
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
src/cron-paths.h
|
||||
anacron/anacron-paths.h
|
46
debian/control
vendored
Normal file
46
debian/control
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
Source: cronie
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Lance Lin <LQi254@protonmail.com>
|
||||
Uploaders: Georges Khaznadar <georgesk@debian.org>
|
||||
Build-Depends:
|
||||
debhelper-compat (= 13),
|
||||
libpam0g-dev,
|
||||
libselinux1-dev [linux-any],
|
||||
libaudit-dev [linux-any]
|
||||
Rules-Requires-Root: no
|
||||
Standards-Version: 4.6.0
|
||||
Homepage: https://github.com/cronie-crond/cronie
|
||||
Vcs-Git: https://salsa.debian.org/debian/cronie.git
|
||||
Vcs-Browser: https://salsa.debian.org/debian/cronie
|
||||
|
||||
Package: cronie
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Pre-Depends:
|
||||
${misc:Pre-Depends},
|
||||
cron-daemon-common
|
||||
Depends:
|
||||
${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
adduser,
|
||||
lsb-base (>= 3.0-6),
|
||||
libpam-runtime (>= 1.0.1-11),
|
||||
sensible-utils
|
||||
Recommends:
|
||||
default-mta | mail-transport-agent
|
||||
Suggests:
|
||||
anacron (>= 2.0-1)
|
||||
Provides: cron-daemon, cron
|
||||
Conflicts: cron
|
||||
Replaces: cron
|
||||
Description: Process Scheduling Daemon
|
||||
cronie is a daemon that runs specified programs at scheduled times and
|
||||
optionally mails generated output to the user. It is a fork of the original
|
||||
ISC cron and contains many improvements, such as:
|
||||
* inotify support (Linux only)
|
||||
* clustering support
|
||||
* full PAM support
|
||||
.
|
||||
cronie is fully compatible with ISC cron (Debian's standard job scheduler),
|
||||
and can be used as a drop-in replacement for it.
|
135
debian/copyright
vendored
Normal file
135
debian/copyright
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: cronie
|
||||
Upstream-Contact: Marcela Mašláňová <mmaslano@redhat.com>
|
||||
Source: https://github.com/cronie-crond/cronie
|
||||
|
||||
Files: *
|
||||
Copyright: 1988,1989,1990,1993,1994, The Regents of the University of California
|
||||
1997,2000, Internet Software Consortium, Inc.
|
||||
2004, Internet Systems Consortium, Inc. ("ISC")
|
||||
1997-2019, Red Hat, Inc.
|
||||
2000,2002, Todd C. Miller
|
||||
2010, Colin Dean
|
||||
License: ISC
|
||||
|
||||
Files: src/popen.c
|
||||
Copyright: 1989,1993,1994,2005, The Regents of the University of California
|
||||
License: BSD-2-clause
|
||||
|
||||
Files: src/bitstring.h
|
||||
Copyright: 1989,1993,2003, The Regents of the University of California
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: anacron/*
|
||||
Copyright: 1998, Itai Tzur <itzur@actcom.co.il>
|
||||
1999, Sean 'Shaleh' Perry <shaleh@debian.org>
|
||||
2004, Pascal Hakim <pasc@redellipse.net>
|
||||
2009-2019, Red Hat, Inc.
|
||||
License: GPL-2+
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2010-2019, Christian Kastner <ckk@debian.org>
|
||||
2018, Andreas Henriksson <andreas@fatal.se>
|
||||
License: GPL-3+
|
||||
|
||||
Files: debian/patches/*
|
||||
Copyright: 2019, Christian Kastner <ckk@debian.org>
|
||||
License: ISC
|
||||
|
||||
License: ISC
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
License: BSD-2-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
License: BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
License: GPL-2+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
.
|
||||
On Debian systems, the full text of the GNU General Public
|
||||
License version 2 can be found in the file
|
||||
"/usr/share/common-licenses/GPL-2".
|
||||
|
||||
License: GPL-3+
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the full text of the GNU General Public
|
||||
License version 3 can be found in the file
|
||||
"/usr/share/common-licenses/GPL-3".
|
||||
|
13
debian/cronie.default
vendored
Normal file
13
debian/cronie.default
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Defaults for cronie initscript
|
||||
# This is a POSIX shell fragment
|
||||
|
||||
# Some additional options for the daemon
|
||||
# See cron(8) for all options and a detailed explanation of these
|
||||
#
|
||||
# -m <cmd> shell command to use for sending mail instead of sendmail(8)
|
||||
# -p lift some restrictions on user crontabs (owner, mode, type)
|
||||
# -P Don't set PATH; instead, inherit it from the environment
|
||||
# -c enable clustering support
|
||||
# -s send job output to syslog instead of mail
|
||||
#
|
||||
DAEMON_ARGS=""
|
6
debian/cronie.dirs
vendored
Normal file
6
debian/cronie.dirs
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
etc/cron.d
|
||||
etc/cron.hourly
|
||||
etc/cron.daily
|
||||
etc/cron.weekly
|
||||
etc/cron.monthly
|
||||
var/spool/cron/crontabs
|
87
debian/cronie.init
vendored
Normal file
87
debian/cronie.init
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: cronie
|
||||
# Required-Start: $remote_fs $syslog $time
|
||||
# Required-Stop: $remote_fs $syslog $time
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop:
|
||||
# Short-Description: time-based job scheduler
|
||||
# Description: cronie is a daemon that runs specified programs at
|
||||
# scheduled times and optionally mails generated output
|
||||
# to the user.
|
||||
### END INIT INFO
|
||||
|
||||
# Author: Christian Kastner <ckk@debian.org>
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC="time-based job scheduler"
|
||||
NAME=cronie
|
||||
DAEMON_NAME=crond
|
||||
DAEMON=/usr/sbin/$DAEMON_NAME
|
||||
DAEMON_ARGS=""
|
||||
PIDFILE=/var/run/$DAEMON_NAME.pid
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
# Exit if the package is not installed
|
||||
[ -x $DAEMON ] || exit 0
|
||||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
. /lib/init/vars.sh
|
||||
|
||||
# Define LSB log_* functions.
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
do_start()
|
||||
{
|
||||
start_daemon -p $PIDFILE $DAEMON $DAEMON_ARGS
|
||||
}
|
||||
|
||||
do_stop()
|
||||
{
|
||||
killproc -p $PIDFILE $DAEMON
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
|
||||
do_start
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 || exit 0 ;;
|
||||
2|3) [ "$VERBOSE" != no ] && log_end_msg 1 || exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
stop)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|3) [ "$VERBOSE" != no ] && log_end_msg 0 || exit 0 ;;
|
||||
*) [ "$VERBOSE" != no ] && log_end_msg 1 || exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
status_of_proc -p $PIDFILE "$DAEMON" "$DAEMON_NAME" && exit 0 || exit $?
|
||||
;;
|
||||
restart|force-reload)
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
do_start
|
||||
case "$?" in
|
||||
0) log_end_msg 0 ;;
|
||||
1) log_end_msg 1 ;; # Old process is still running
|
||||
*) log_end_msg 1 ;; # Failed to start
|
||||
esac
|
||||
else
|
||||
# Failed to stop
|
||||
log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
21
debian/cronie.pam
vendored
Normal file
21
debian/cronie.pam
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# The PAM configuration file for cronie (cron daemon)
|
||||
|
||||
# Access control using /etc/security/access.conf
|
||||
account required pam_access.so
|
||||
|
||||
# Set the loginuid process attribute
|
||||
session required pam_loginuid.so
|
||||
|
||||
# Read environment variables from pam_env's default files, /etc/environment
|
||||
# and /etc/security/pam_env.conf.
|
||||
session required pam_env.so
|
||||
|
||||
# In addition to the above, read system locale information
|
||||
session required pam_env.so envfile=/etc/default/locale
|
||||
|
||||
# Sets up user limits
|
||||
session required pam_limits.so
|
||||
|
||||
@include common-account
|
||||
@include common-session-noninteractive
|
||||
@include common-auth
|
65
debian/cronie.postinst
vendored
Normal file
65
debian/cronie.postinst
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Analogous to Debian's ISC cron postinst script (for compatibility reasons)
|
||||
crondir="/var/spool/cron"
|
||||
action="$1"
|
||||
|
||||
if [ "$action" != configure ]
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
# Make sure group "crontab" exists (needed for running SGID)
|
||||
getent group crontab > /dev/null 2>&1 || addgroup --system crontab
|
||||
|
||||
# Make crontab(1) SGID
|
||||
if ! dpkg-statoverride --list /usr/bin/crontab > /dev/null
|
||||
then
|
||||
dpkg-statoverride --update --add root crontab 2755 /usr/bin/crontab
|
||||
fi
|
||||
|
||||
# Adjust permissions for spool dir
|
||||
# Can't use dpkg-statoverride for this because it doesn't cooperate nicely
|
||||
# with cron alternatives such as bcron
|
||||
if [ -d $crondir/crontabs ]
|
||||
then
|
||||
# This must be in sync with misc.c:check_spool_dir()
|
||||
chown root:crontab $crondir/crontabs
|
||||
chmod 1730 $crondir/crontabs
|
||||
|
||||
cd $crondir/crontabs
|
||||
set +e
|
||||
|
||||
# Iterate over each entry in the spool directory, perform some sanity
|
||||
# checks (see CVE-2017-9525), and chown/chgroup the crontabs
|
||||
for tab_name in *
|
||||
do
|
||||
[ "$tab_name" = "*" ] && continue
|
||||
tab_links=`stat -c '%h' "$tab_name"`
|
||||
tab_owner=`stat -c '%U' "$tab_name"`
|
||||
|
||||
if [ ! -f "$tab_name" ]
|
||||
then
|
||||
echo "Warning: $tab_name is not a regular file!"
|
||||
continue
|
||||
elif [ "$tab_links" -ne 1 ]
|
||||
then
|
||||
echo "Warning: $tab_name has more than one hard link!"
|
||||
continue
|
||||
elif [ "$tab_owner" != "$tab_name" ]
|
||||
then
|
||||
echo "Warning: $tab_name name differs from owner $tab_owner!"
|
||||
continue
|
||||
fi
|
||||
|
||||
chown "$tab_owner:crontab" "$tab_name"
|
||||
chmod 600 "$tab_name"
|
||||
done
|
||||
set -e
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
11
debian/cronie.postrm
vendored
Normal file
11
debian/cronie.postrm
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ "$1" = "purge" ]
|
||||
then
|
||||
rm -f /etc/cron.allow /etc/cron.deny
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
6
debian/cronie.prerm
vendored
Normal file
6
debian/cronie.prerm
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
2
debian/docs
vendored
Normal file
2
debian/docs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
NEWS
|
||||
README
|
0
debian/etc/cronie.deny
vendored
Normal file
0
debian/etc/cronie.deny
vendored
Normal file
12
debian/etc/crontab.system
vendored
Normal file
12
debian/etc/crontab.system
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# /etc/crontab: system-wide crontab
|
||||
# See crontab(5)
|
||||
|
||||
# Set PATH to system default
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
# m h dom mon dow user command
|
||||
17 * * * * root cd / && run-parts --report /etc/cron.hourly
|
||||
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
|
||||
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
|
||||
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
|
||||
#
|
2
debian/etc/placeholder
vendored
Normal file
2
debian/etc/placeholder
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# DO NOT REMOVE
|
||||
# this file prevents dpkg from removing this directory
|
10
debian/gbp.conf
vendored
Normal file
10
debian/gbp.conf
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
[DEFAULT]
|
||||
pristine-tar = True
|
||||
debian-branch = debian/master
|
||||
upstream-branch = upstream/latest
|
||||
|
||||
[buildpackage]
|
||||
sign-tags = True
|
||||
|
||||
[pq]
|
||||
patch-numbers = False
|
75
debian/patches/Debian-specific-paths-and-features.patch
vendored
Normal file
75
debian/patches/Debian-specific-paths-and-features.patch
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Thu, 28 Jul 2011 11:15:01 +0200
|
||||
Subject: Debian-specific paths and features
|
||||
|
||||
Use Debian-specific paths and features. For example, the spool dir differs from
|
||||
upstream, and we always build to use syslog.
|
||||
|
||||
Forwarded: not-needed
|
||||
Last-Update: 2011-07-28
|
||||
---
|
||||
man/cron.8 | 15 ++-------------
|
||||
man/crontab.1 | 2 +-
|
||||
man/crontab.5 | 2 +-
|
||||
3 files changed, 4 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/man/cron.8
|
||||
+++ b/man/cron.8
|
||||
@@ -41,7 +41,7 @@
|
||||
.PP
|
||||
.I Cron
|
||||
searches
|
||||
-.I /var/spool/cron
|
||||
+.I /var/spool/cron/crontabs
|
||||
for crontab files which are named after user accounts;
|
||||
together with the system crontab
|
||||
.IR /etc/crontab ,
|
||||
@@ -88,7 +88,7 @@
|
||||
.IR /etc/cron.d/
|
||||
directory that contains system cronjobs stored for different users.
|
||||
.TP
|
||||
-.IR /var/spool/cron
|
||||
+.IR /var/spool/cron/crontabs
|
||||
directory that contains user crontables created by the
|
||||
.BR crontab (1)
|
||||
command.
|
||||
@@ -181,17 +181,6 @@
|
||||
.TP
|
||||
.B "\-V"
|
||||
Print version and exit.
|
||||
-.SH SIGNALS
|
||||
-When the
|
||||
-.I SIGHUP
|
||||
-is received, the
|
||||
-.I Cron
|
||||
-daemon will close and reopen its log file. This proves to be useful in
|
||||
-scripts which rotate and age log files. Naturally, this is not relevant
|
||||
-if
|
||||
-.I Cron
|
||||
-was built to use
|
||||
-.IR syslog (3).
|
||||
.SH CLUSTERING SUPPORT
|
||||
In this version of
|
||||
.IR Cron
|
||||
--- a/man/crontab.1
|
||||
+++ b/man/crontab.1
|
||||
@@ -68,7 +68,7 @@
|
||||
In this version of
|
||||
.IR Cron
|
||||
it is possible to use a network-mounted shared
|
||||
-.I /var/spool/cron
|
||||
+.I /var/spool/cron/crontabs
|
||||
across a cluster of hosts and specify that only one of the hosts should
|
||||
run the crontab jobs in the particular directory at any one time. You
|
||||
may also use
|
||||
--- a/man/crontab.5
|
||||
+++ b/man/crontab.5
|
||||
@@ -315,7 +315,7 @@
|
||||
.SH FILES
|
||||
.I /etc/crontab
|
||||
main system crontab file.
|
||||
-.I /var/spool/cron/
|
||||
+.I /var/spool/cron/crontabs
|
||||
a directory for storing crontabs defined by users.
|
||||
.I /etc/cron.d/
|
||||
a directory for storing system crontabs.
|
36
debian/patches/Extend-support-for-kFreeBSD-and-GNU-HURD.patch
vendored
Normal file
36
debian/patches/Extend-support-for-kFreeBSD-and-GNU-HURD.patch
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Sun, 7 Aug 2011 19:48:09 +0200
|
||||
Subject: Extend support for kFreeBSD and GNU HURD
|
||||
|
||||
Extend some of the #ifdefs to include kFreeBSD and HURD where it's obviously OK
|
||||
to do so
|
||||
|
||||
Forwarded: no
|
||||
Last-Update: 2011-08-07
|
||||
---
|
||||
src/entry.c | 2 +-
|
||||
src/pathnames.h | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/src/entry.c
|
||||
+++ b/src/entry.c
|
||||
@@ -403,7 +403,7 @@
|
||||
}
|
||||
else
|
||||
log_it("CRON", getpid(), "ERROR", "can't set LOGNAME", 0);
|
||||
-#if defined(BSD) || defined(__linux)
|
||||
+#if defined(BSD) || defined(__linux) || defined(__GLIBC__) || defined(__gnu_hurd__)
|
||||
if (glue_strings(envstr, sizeof envstr, "USER", pw->pw_name, '=')) {
|
||||
if ((tenvp = env_set(e->envp, envstr)) == NULL) {
|
||||
ecode = e_memory;
|
||||
--- a/src/pathnames.h
|
||||
+++ b/src/pathnames.h
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef _PATHNAMES_H_
|
||||
#define _PATHNAMES_H_
|
||||
|
||||
-#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX)
|
||||
+#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX) || defined(__GLIBC__) || defined(__gnu_hurd__)
|
||||
# include <paths.h>
|
||||
#endif /*BSD*/
|
||||
|
27
debian/patches/Hurd-workaround-for-PATH_MAX.patch
vendored
Normal file
27
debian/patches/Hurd-workaround-for-PATH_MAX.patch
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Tue, 5 Nov 2019 07:52:09 +0100
|
||||
Subject: Hurd workaround for PATH_MAX
|
||||
|
||||
PATH_MAX is not defined on GNU Hurd, which is legal according to POSIX.
|
||||
|
||||
https://www.gnu.org/software/hurd/hurd/porting/guidelines.html
|
||||
|
||||
Bug-Debian: https://bugs.debian.org/638048
|
||||
---
|
||||
src/macros.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/src/macros.h
|
||||
+++ b/src/macros.h
|
||||
@@ -43,6 +43,11 @@
|
||||
#define DEBUGGING FALSE
|
||||
#endif
|
||||
|
||||
+/* Gnu Hurd has no limit on pathnames */
|
||||
+#if !defined PATH_MAX && defined __GNU__
|
||||
+#define PATH_MAX 4096
|
||||
+#endif
|
||||
+
|
||||
#define INIT_PID 1 /* parent of orphans */
|
||||
#define READ_PIPE 0 /* which end of a pipe pair do you read? */
|
||||
#define WRITE_PIPE 1 /* or write to? */
|
133
debian/patches/Manpage-and-typo-fixes.patch
vendored
Normal file
133
debian/patches/Manpage-and-typo-fixes.patch
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Thu, 28 Jul 2011 11:07:40 +0200
|
||||
Subject: Manpage and typo fixes
|
||||
|
||||
Correct some errors or clarify sections in the manpages; fix some typos
|
||||
---
|
||||
man/cron.8 | 43 ++++++++++++++++---------------------------
|
||||
man/crontab.1 | 2 +-
|
||||
man/crontab.5 | 2 +-
|
||||
src/cron.c | 2 +-
|
||||
4 files changed, 19 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/man/cron.8
|
||||
+++ b/man/cron.8
|
||||
@@ -37,23 +37,15 @@
|
||||
.B -V
|
||||
.SH DESCRIPTION
|
||||
.I Cron
|
||||
-is started from
|
||||
-.I /etc/rc.d/init.d
|
||||
-or
|
||||
-.I /etc/init.d
|
||||
-when classical sysvinit scripts are used. In case systemd is enabled, then unit file is installed into
|
||||
-.I /lib/systemd/system/crond.service
|
||||
-and daemon is started by
|
||||
-.I systemctl start crond.service
|
||||
-command. It returns immediately, thus, there is no need to need to start it with
|
||||
-the '&' parameter.
|
||||
+is automatically started at boot time.
|
||||
.PP
|
||||
.I Cron
|
||||
searches
|
||||
.I /var/spool/cron
|
||||
-for crontab files which are named after accounts in
|
||||
-.I /etc/passwd;
|
||||
-The found crontabs are loaded into the memory.
|
||||
+for crontab files which are named after user accounts;
|
||||
+together with the system crontab
|
||||
+.IR /etc/crontab ,
|
||||
+the found crontabs are loaded into the memory.
|
||||
.I Cron
|
||||
also searches for
|
||||
any files in the
|
||||
@@ -71,12 +63,11 @@
|
||||
option.
|
||||
.PP
|
||||
There are two ways how changes in crontables are checked. The first
|
||||
-method is checking the modtime of a file. The second method is using the
|
||||
-inotify support. Using of inotify is logged in the
|
||||
-.I /var/log/cron
|
||||
-log after the daemon is started. The inotify support checks for changes
|
||||
-in all crontables and accesses the hard disk only when a change is
|
||||
-detected.
|
||||
+method is checking the modtime of a file. The second method
|
||||
+is using inotify support, which is only available on Linux.
|
||||
+When the daemon uses inotify, it logs this fact to syslog on startup.
|
||||
+The inotify support checks for changes in all crontables and accesses the
|
||||
+hard disk only when a change is detected.
|
||||
.PP
|
||||
When using the modtime option,
|
||||
.I Cron
|
||||
@@ -99,13 +90,8 @@
|
||||
.TP
|
||||
.IR /var/spool/cron
|
||||
directory that contains user crontables created by the
|
||||
-.IR crontab
|
||||
-command.
|
||||
-.PP
|
||||
-Note that the
|
||||
.BR crontab (1)
|
||||
-command updates the modtime of the spool directory whenever it changes a
|
||||
-crontab.
|
||||
+command.
|
||||
.PP
|
||||
.SS Daylight Saving Time and other time changes
|
||||
Local time changes of less than three hours, such as those caused by the
|
||||
@@ -153,7 +139,6 @@
|
||||
standard input and send it as a mail message to the recipients specified
|
||||
in the mail headers. Specifying the string
|
||||
.I "off"
|
||||
-(i.e., crond -m off)
|
||||
will disable the sending of mail.
|
||||
.TP
|
||||
.B "\-n"
|
||||
@@ -167,10 +152,14 @@
|
||||
.B "\-f"
|
||||
the same as -n, consistent with other crond implementations.
|
||||
.TP
|
||||
+.B "\-i"
|
||||
+Disables inotify support (if present)
|
||||
+.TP
|
||||
.B "\-p"
|
||||
Allows
|
||||
.I Cron
|
||||
-to accept any user set crontables.
|
||||
+to accept any user set crontables (read: lift owner, type and mode
|
||||
+restrictions)
|
||||
.TP
|
||||
.B "\-P"
|
||||
Don't set PATH. PATH is instead inherited from the environment.
|
||||
--- a/man/crontab.1
|
||||
+++ b/man/crontab.1
|
||||
@@ -109,7 +109,7 @@
|
||||
.IR /etc/cron.d/
|
||||
directory.
|
||||
.PP
|
||||
-The temporary directory can be set in an environment variable. If it is
|
||||
+The temporary directory can be set using the environment variable $TMPDIR. If it is
|
||||
not set by the user, the
|
||||
.I /tmp
|
||||
directory is used.
|
||||
--- a/man/crontab.5
|
||||
+++ b/man/crontab.5
|
||||
@@ -268,7 +268,7 @@
|
||||
# run at 2:15pm on the first of every month -- output mailed to paul
|
||||
15 14 1 * * $HOME/bin/monthly
|
||||
# run at 10 pm on weekdays, annoy Joe
|
||||
-0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
|
||||
+0 22 * * 1-5 mail \-s "It's 10pm" joe%Joe,%%Where are your kids?%
|
||||
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
|
||||
5 4 * * sun echo "run at 5 after 4 every sunday"
|
||||
.fi
|
||||
--- a/src/cron.c
|
||||
+++ b/src/cron.c
|
||||
@@ -179,7 +179,7 @@
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -h print this message \n");
|
||||
- fprintf(stderr, " -i deamon runs without inotify support\n");
|
||||
+ fprintf(stderr, " -i daemon runs without inotify support\n");
|
||||
fprintf(stderr, " -m <comm> off, or specify preferred client for sending mails\n");
|
||||
fprintf(stderr, " -n run in foreground\n");
|
||||
fprintf(stderr, " -f run in foreground, the same as -n\n");
|
24
debian/patches/Rename-PAM-service-to-cronie.patch
vendored
Normal file
24
debian/patches/Rename-PAM-service-to-cronie.patch
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Thu, 28 Jul 2011 11:11:45 +0200
|
||||
Subject: Rename PAM service to cronie
|
||||
|
||||
Upstream uses "crond"; we switch to "cron" to avoid confusion with Debian's ISC
|
||||
cron (it uses "cron" but that might change).
|
||||
|
||||
Forwarded: not-needed
|
||||
Last-Update: 2011-07-28
|
||||
---
|
||||
src/security.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/src/security.c
|
||||
+++ b/src/security.c
|
||||
@@ -195,7 +195,7 @@
|
||||
int cron_start_pam(struct passwd *pw) {
|
||||
int retcode = 0;
|
||||
|
||||
- retcode = pam_start("crond", pw->pw_name, &conv, &pamh);
|
||||
+ retcode = pam_start("cronie", pw->pw_name, &conv, &pamh);
|
||||
PAM_FAIL_CHECK;
|
||||
retcode = pam_set_item(pamh, PAM_TTY, "cron");
|
||||
PAM_FAIL_CHECK;
|
40
debian/patches/Unbundle-anacron.patch
vendored
Normal file
40
debian/patches/Unbundle-anacron.patch
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Thu, 28 Jul 2011 11:01:03 +0200
|
||||
Subject: Unbundle anacron
|
||||
|
||||
Upstream has integrated anacron into cronie. Debian has its own package, so
|
||||
we unbundle it (mostly by removing references to it).
|
||||
|
||||
Forwarded: not-needed
|
||||
Last-Update: 2011-07-28
|
||||
---
|
||||
man/cron.8 | 11 +++--------
|
||||
1 file changed, 3 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/man/cron.8
|
||||
+++ b/man/cron.8
|
||||
@@ -56,8 +56,7 @@
|
||||
The found crontabs are loaded into the memory.
|
||||
.I Cron
|
||||
also searches for
|
||||
-.I /etc/anacrontab
|
||||
-and any files in the
|
||||
+any files in the
|
||||
.I /etc/cron.d
|
||||
directory, which have a different format (see
|
||||
.BR crontab (5)).
|
||||
@@ -91,12 +90,8 @@
|
||||
checks these files and directories:
|
||||
.TP
|
||||
.IR /etc/crontab
|
||||
-system crontab. Nowadays the file is empty by default. Originally it
|
||||
-was usually used to run daily, weekly, monthly jobs. By default these
|
||||
-jobs are now run through anacron which reads
|
||||
-.IR /etc/anacrontab
|
||||
-configuration file. See
|
||||
-.BR anacrontab (5)
|
||||
+system crontab, usually used to run daily, weekly, monthly jobs. See
|
||||
+.BR crontab (5)
|
||||
for more details.
|
||||
.TP
|
||||
.IR /etc/cron.d/
|
27
debian/patches/Unbundle-upstream-PAM-config.patch
vendored
Normal file
27
debian/patches/Unbundle-upstream-PAM-config.patch
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
From: Christian Kastner <ckk@kvr.at>
|
||||
Date: Thu, 31 Oct 2019 22:16:13 +0100
|
||||
Subject: Unbundle upstream PAM config
|
||||
|
||||
We supply our own PAM config, tailored to the Debian setup.
|
||||
|
||||
Last-Update: 2019-10-31
|
||||
---
|
||||
Makefile.am | 7 -------
|
||||
1 file changed, 7 deletions(-)
|
||||
|
||||
--- a/Makefile.am
|
||||
+++ b/Makefile.am
|
||||
@@ -24,13 +24,6 @@
|
||||
contrib/cronie.systemd \
|
||||
anacron/ChangeLog.anacron
|
||||
|
||||
-if PAM
|
||||
-pamdir = $(sysconfdir)/pam.d
|
||||
-dist_pam_DATA = pam/crond
|
||||
-else
|
||||
-EXTRA_DIST += pam/crond
|
||||
-endif
|
||||
-
|
||||
include anacron/Makemodule.am
|
||||
include man/Makemodule.am
|
||||
include src/Makemodule.am
|
27
debian/patches/cronie-service-debianization.patch
vendored
Normal file
27
debian/patches/cronie-service-debianization.patch
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
From: Andreas Henriksson <andreas@fatal.se>
|
||||
Date: Mon, 28 Oct 2019 19:33:53 +0100
|
||||
Subject: Adjust the cronie.service file for debian use
|
||||
|
||||
Use default file instead of sysconfig, as shipped by this
|
||||
package (debian/cronie.default) and also modify the variable
|
||||
on ExecStart line as for what is used in the shipped default
|
||||
file.
|
||||
|
||||
Forwarded: not-needed
|
||||
---
|
||||
contrib/cronie.systemd | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/contrib/cronie.systemd
|
||||
+++ b/contrib/cronie.systemd
|
||||
@@ -3,8 +3,8 @@
|
||||
After=auditd.service nss-user-lookup.target systemd-user-sessions.service time-sync.target ypbind.service autofs.service
|
||||
|
||||
[Service]
|
||||
-EnvironmentFile=/etc/sysconfig/crond
|
||||
-ExecStart=/usr/sbin/crond -n $CRONDARGS
|
||||
+EnvironmentFile=/etc/default/cronie
|
||||
+ExecStart=/usr/sbin/crond -n $DAEMON_ARGS
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillMode=process
|
||||
Restart=on-failure
|
8
debian/patches/series
vendored
Normal file
8
debian/patches/series
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
Unbundle-anacron.patch
|
||||
Manpage-and-typo-fixes.patch
|
||||
Rename-PAM-service-to-cronie.patch
|
||||
Unbundle-upstream-PAM-config.patch
|
||||
Debian-specific-paths-and-features.patch
|
||||
Extend-support-for-kFreeBSD-and-GNU-HURD.patch
|
||||
cronie-service-debianization.patch
|
||||
Hurd-workaround-for-PATH_MAX.patch
|
76
debian/rules
vendored
Executable file
76
debian/rules
vendored
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# For DEB_HOST_ARCH_OS
|
||||
include /usr/share/dpkg/architecture.mk
|
||||
|
||||
# Add build flags
|
||||
export DEB_CFLAGS_MAINT_APPEND = -Wall
|
||||
|
||||
# Add hardening flags
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
# Build the config options string
|
||||
CONFIG_OPTIONS =
|
||||
|
||||
# anacron is still being provided by src:anacron
|
||||
CONFIG_OPTIONS += --disable-anacron
|
||||
|
||||
# Default EDITOR path
|
||||
CONFIG_OPTIONS += --with-editor=/usr/bin/sensible-editor
|
||||
|
||||
# PAM is enabled by default
|
||||
ifeq (,$(findstring nopam,$(DEB_BUILD_OPTIONS)))
|
||||
CONFIG_OPTIONS += --with-pam
|
||||
endif
|
||||
|
||||
##########################
|
||||
### Linux-only options ###
|
||||
ifeq ($(DEB_HOST_ARCH_OS), linux)
|
||||
|
||||
# SELINUX is enabled by default
|
||||
ifeq (,$(findstring noselinux,$(DEB_BUILD_OPTIONS)))
|
||||
CONFIG_OPTIONS += --with-selinux
|
||||
endif
|
||||
|
||||
# inotify is enabled by default
|
||||
ifeq (,$(findstring noinotify,$(DEB_BUILD_OPTIONS)))
|
||||
CONFIG_OPTIONS += --with-inotify
|
||||
endif
|
||||
|
||||
# audit is disabled by default
|
||||
ifneq (,$(findstring withaudit,$(DEB_BUILD_OPTIONS)))
|
||||
CONFIG_OPTIONS += --with-audit
|
||||
endif
|
||||
|
||||
endif
|
||||
##### End Linux-only #####
|
||||
##########################
|
||||
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
# Set SPOOL_DIR to Debian's traditional location for crontabs (see Policy)
|
||||
# Set CRON_GROUP to "crontab" to enable SGID functionality (avoids SUID)
|
||||
override_dh_auto_configure:
|
||||
SPOOL_DIR=/var/spool/cron/crontabs \
|
||||
dh_auto_configure CRON_GROUP=crontab -- $(CONFIG_OPTIONS)
|
||||
|
||||
override_dh_install:
|
||||
dh_install
|
||||
# Create /etc/cron.deny to allow crontab(1) for all users by default
|
||||
install -m 644 debian/etc/cronie.deny debian/cronie/etc/cron.deny
|
||||
# System-wide crontab: IS NOT INSTALLED HERE: SEE CON-DAEMON-COMMON
|
||||
#install -m 644 debian/etc/crontab.system debian/cronie/etc/crontab
|
||||
# Placeholders for dpkg: ARE NOT INSTALLED HERE: SEE CON-DAEMON-COMMON
|
||||
#install -m 644 debian/etc/placeholder debian/cronie/etc/cron.d/.placeholder
|
||||
#install -m 644 debian/etc/placeholder debian/cronie/etc/cron.hourly/.placeholder
|
||||
#install -m 644 debian/etc/placeholder debian/cronie/etc/cron.daily/.placeholder
|
||||
#install -m 644 debian/etc/placeholder debian/cronie/etc/cron.weekly/.placeholder
|
||||
#install -m 644 debian/etc/placeholder debian/cronie/etc/cron.monthly/.placeholder
|
||||
# systemd service file
|
||||
install -d -m 755 debian/cronie/lib/systemd/system/
|
||||
install -m 644 contrib/cronie.systemd debian/cronie/lib/systemd/system/cronie.service
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
8
debian/watch
vendored
Normal file
8
debian/watch
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
version=4
|
||||
|
||||
# using Github's API with tags
|
||||
|
||||
opts="searchmode=plain,\
|
||||
filenamemangle=s%v?@ANY_VERSION@%@PACKAGE@-$1.tar.gz%" \
|
||||
https://api.github.com/repos/cronie-crond/cronie/tags?per_page=100 \
|
||||
https://api.github.com/repos/[^/]+/[^/]+/tarball/refs/tags/v?@ANY_VERSION@
|
791
depcomp
Executable file
791
depcomp
Executable file
@ -0,0 +1,791 @@
|
||||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2018 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
518
install-sh
Executable file
518
install-sh
Executable file
@ -0,0 +1,518 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2018-03-11.20; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
# Note that $RANDOM variable is not portable (e.g. dash); Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p' feature.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
16
man/Makemodule.am
Normal file
16
man/Makemodule.am
Normal file
@ -0,0 +1,16 @@
|
||||
dist_man_MANS = \
|
||||
man/cron.8 \
|
||||
man/crond.8 \
|
||||
man/cronnext.1 \
|
||||
man/crontab.1 \
|
||||
man/crontab.5
|
||||
|
||||
anacron_man = \
|
||||
man/anacrontab.5 \
|
||||
man/anacron.8
|
||||
|
||||
EXTRA_DIST += $(anacron_man)
|
||||
|
||||
if ANACRON
|
||||
dist_man_MANS += $(anacron_man)
|
||||
endif
|
217
man/anacron.8
Normal file
217
man/anacron.8
Normal file
@ -0,0 +1,217 @@
|
||||
.TH ANACRON 8 2012-11-22 "cronie" "System Administration"
|
||||
.SH NAME
|
||||
anacron \- runs commands periodically
|
||||
.SH SYNOPSIS
|
||||
.B anacron \fR[\fB-s\fR] [\fB-f\fR] [\fB-n\fR] [\fB-d\fR] [\fB-q\fR]
|
||||
[\fB-t anacrontab\fR] [\fB-S spooldir\fR] [\fIjob\fR]
|
||||
.br
|
||||
.B anacron \fR[\fB-S spooldir\fR] -u [\fB-t anacrontab\fR] \fR[\fIjob\fR]
|
||||
.br
|
||||
.B anacron \fR[\fB-V\fR|\fB-h\fR]
|
||||
.br
|
||||
.B anacron -T \fR[\fB-t anacrontab\fR]
|
||||
.SH DESCRIPTION
|
||||
.B Anacron
|
||||
is used to execute commands periodically, with a frequency specified in
|
||||
days. Unlike
|
||||
.BR cron(8) ,
|
||||
it does not assume that the machine is running continuously. Hence, it
|
||||
can be used on machines that are not running 24 hours a day to control
|
||||
regular jobs as daily, weekly, and monthly jobs.
|
||||
.PP
|
||||
Anacron reads a list of jobs from the
|
||||
.I /etc/anacrontab
|
||||
configuration file (see
|
||||
.BR anacrontab (5)).
|
||||
This file contains the list of jobs that Anacron controls. Each job
|
||||
entry specifies a period in days, a delay in minutes, a unique job
|
||||
identifier, and a shell command.
|
||||
.PP
|
||||
For each job, Anacron checks whether this job has been executed in the
|
||||
last
|
||||
.B n
|
||||
days, where
|
||||
.B n
|
||||
is the time period specified for that job. If a job has not been
|
||||
executed in
|
||||
.B n
|
||||
days or more, Anacron runs the job's shell command, after waiting for the
|
||||
number of minutes specified as the delay parameter.
|
||||
.PP
|
||||
After the command exits, Anacron records the date (excludes the hour) in
|
||||
a special timestamp file for that job, so it knows when to execute that
|
||||
job again.
|
||||
.PP
|
||||
When there are no more jobs to be run, Anacron exits.
|
||||
.PP
|
||||
Anacron only considers jobs whose identifier, as specified in
|
||||
.BR anacrontab (5),
|
||||
matches any of the
|
||||
.I job
|
||||
command-line arguments. The
|
||||
.I job
|
||||
command-line arguments can be represented by shell wildcard patterns (be
|
||||
sure to protect them from your shell with adequate quoting). Specifying
|
||||
no
|
||||
.I job
|
||||
command-line arguments is equivalent to specifying "*" (that is, all
|
||||
jobs are considered by Anacron).
|
||||
.PP
|
||||
Unless Anacron is run with the
|
||||
.B \-d
|
||||
option (specified below), it forks to the background when it starts, and
|
||||
any parent processes exit immediately.
|
||||
.PP
|
||||
Unless Anacron is run with the
|
||||
.B \-s
|
||||
or
|
||||
.B \-n
|
||||
options, it starts jobs immediately when their delay is over. The
|
||||
execution of different jobs is completely independent.
|
||||
.PP
|
||||
If an executed job generates any output to standard output or to standard
|
||||
error, the output is mailed to the user under whom Anacron is running
|
||||
(usually root), or to the address specified in the
|
||||
.B MAILTO
|
||||
environment variable in the
|
||||
.I /etc/anacrontab
|
||||
file, if such exists. If the
|
||||
.B LOGNAME
|
||||
environment variable is set, it is used in the From: field of the mail.
|
||||
.PP
|
||||
Any informative messages generated by Anacron are sent to
|
||||
.BR syslogd (8)
|
||||
or
|
||||
.BR rsyslogd (8)
|
||||
under with facility set to
|
||||
.B cron
|
||||
and priority set to
|
||||
.BR notice .
|
||||
Any error messages are sent with the priority
|
||||
.BR error .
|
||||
.PP
|
||||
"Active" jobs (i.e., jobs that Anacron already decided to run and are now
|
||||
waiting for their delay to pass, and jobs that are currently being
|
||||
executed by Anacron), are "locked", so that other copies of Anacron
|
||||
cannot run them at the same time.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-f
|
||||
Forces execution of all jobs, ignoring any timestamps.
|
||||
.TP
|
||||
.B \-u
|
||||
Updates the timestamps of all jobs to the current date, but does not run
|
||||
any.
|
||||
.TP
|
||||
.B \-s
|
||||
Serializes execution of jobs. Anacron does not start a new job before the
|
||||
previous one finished.
|
||||
.TP
|
||||
.B \-n
|
||||
Runs jobs immediately and ignores the specified delays in the
|
||||
.I /etc/anacrontab
|
||||
file. This options implies
|
||||
.BR -s .
|
||||
.TP
|
||||
.B \-d
|
||||
Does not fork Anacron to the background. In this mode, Anacron will
|
||||
output informational messages to standard error, as well as to syslog.
|
||||
The output of any job is mailed by Anacron.
|
||||
.TP
|
||||
.B \-q
|
||||
Suppresses any messages to standard error. Only applicable with
|
||||
.BR -d .
|
||||
.TP
|
||||
.B -t some_anacrontab
|
||||
Uses the specified anacrontab, rather than the
|
||||
.I /etc/anacrontab
|
||||
default one.
|
||||
.TP
|
||||
.B -T
|
||||
Anacrontab testing. Tests the
|
||||
.I /etc/anacrontab
|
||||
configuration file for validity. If there is an error in the file, it is
|
||||
shown on the standard output and Anacron returns the value of 1. Valid
|
||||
anacrontabs return the value of 0.
|
||||
.TP
|
||||
.B -S spooldir
|
||||
Uses the specified spooldir to store timestamps in. This option is
|
||||
required for users who wish to run anacron themselves.
|
||||
.TP
|
||||
.B -V
|
||||
Prints version information, and exits.
|
||||
.TP
|
||||
.B -h
|
||||
Prints short usage message, and exits.
|
||||
.SH SIGNALS
|
||||
After receiving a
|
||||
.B SIGUSR1
|
||||
signal, Anacron waits for any running jobs to finish and then exits.
|
||||
This can be used to stop Anacron cleanly.
|
||||
.SH NOTES
|
||||
Make sure your time-zone is set correctly before Anacron is started since
|
||||
the time-zone affects the date. This is usually accomplished by setting
|
||||
the TZ environment variable, or by installing a
|
||||
.I /usr/lib/zoneinfo/localtime
|
||||
file. See
|
||||
.BR tzset (3)
|
||||
for more information.
|
||||
.PP
|
||||
Timestamp files are created in the spool directory for each job specified
|
||||
in an anacrontab. These files are never removed automatically by
|
||||
Anacron, and should be removed by hand if a job is no longer being
|
||||
scheduled.
|
||||
.SH FILES
|
||||
.TP
|
||||
.I /etc/anacrontab
|
||||
Contains specifications of jobs. See
|
||||
.BR anacrontab (5)
|
||||
for a complete description.
|
||||
.TP
|
||||
.I /var/spool/anacron
|
||||
This directory is used by Anacron for storing timestamp files.
|
||||
.SH "SEE ALSO"
|
||||
.BR anacrontab (5),
|
||||
.BR cron (8),
|
||||
.BR tzset (3)
|
||||
.PP
|
||||
The Anacron
|
||||
.I README
|
||||
file.
|
||||
.SH BUGS
|
||||
Anacron never removes timestamp files. Remove unused files manually.
|
||||
.PP
|
||||
Anacron uses up to two file descriptors for each active job. It may run
|
||||
out of descriptors if there are lots of active jobs. See
|
||||
.B echo $(($(ulimit -n) / 2))
|
||||
for information how many concurent jobs anacron may run.
|
||||
.PP
|
||||
Mail comments, suggestions and bug reports to
|
||||
.MT shaleh@\:(debian.\:org|\:valinux.\:com)
|
||||
Sean 'Shaleh' Perry
|
||||
.ME .
|
||||
.SH AUTHOR
|
||||
Anacron was originally conceived and implemented by
|
||||
.MT schwarz@\:monet.\:m.\:isar.\:de
|
||||
Christian Schwarz
|
||||
.ME .
|
||||
.PP
|
||||
The current implementation is a complete rewrite by
|
||||
.MT itzur@\:actcom.\:co.\:il
|
||||
Itai Tzur
|
||||
.ME .
|
||||
.PP
|
||||
The code base was maintained by
|
||||
.MT shaleh@\:(debian.\:org|\:valinux.\:com)
|
||||
Sean 'Shaleh' Perry
|
||||
.ME .
|
||||
.PP
|
||||
Since 2004, it is maintained by
|
||||
.MT pasc@\:(debian.\:org|\:redellipse.\:net)
|
||||
Pascal Hakim
|
||||
.ME .
|
||||
.PP
|
||||
For Fedora, Anacron is maintained by
|
||||
.MT mmaslano@redhat.\:com
|
||||
Marcela Mašláňová
|
||||
.ME .
|
141
man/anacrontab.5
Normal file
141
man/anacrontab.5
Normal file
@ -0,0 +1,141 @@
|
||||
.TH ANACRONTAB 5 2012-11-22 "cronie" "File Formats"
|
||||
.SH NAME
|
||||
/etc/anacrontab \- configuration file for Anacron
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.I /etc/anacrontab
|
||||
configuration file describes the jobs controlled by
|
||||
.BR anacron (8).
|
||||
It can contain three types of lines: job-description lines, environment
|
||||
assignments, or empty lines.
|
||||
.PP
|
||||
Job-description lines can have the following format:
|
||||
.PP
|
||||
period in days delay in minutes job-identifier command
|
||||
.PP
|
||||
The
|
||||
.I period in days
|
||||
variable specifies the frequency of execution of a job in days. This
|
||||
variable can be represented by an integer or a macro (@daily, @weekly,
|
||||
@monthly), where @daily denotes the same value as the integer 1, @weekly
|
||||
the same as 7, and @monthly specifies that the job is run once a month,
|
||||
independent on the length of the month.
|
||||
.PP
|
||||
The
|
||||
.I delay in minutes
|
||||
variable specifies the number of minutes anacron waits, if necessary,
|
||||
before executing a job. This variable is represented by an integer where
|
||||
0 means no delay.
|
||||
.PP
|
||||
The
|
||||
.I job-identifier
|
||||
variable specifies a unique name of a job which is used in the log files.
|
||||
.PP
|
||||
The
|
||||
.I command
|
||||
variable specifies the command to execute. The command can either be a
|
||||
command such as
|
||||
.B ls /proc >> /tmp/proc
|
||||
or a command to execute a custom script.
|
||||
.PP
|
||||
Environment assignment lines can have the following format:
|
||||
.PP
|
||||
VAR=VALUE
|
||||
.PP
|
||||
Any spaces around
|
||||
.I VAR
|
||||
are removed. No spaces around
|
||||
.I VALUE
|
||||
are allowed (unless you want them to be part of the value). The
|
||||
specified assignment takes effect from the next line until the end of the
|
||||
file, or to the next assignment of the same variable.
|
||||
.PP
|
||||
The
|
||||
.I START_HOURS_RANGE
|
||||
variable defines an interval (in hours) when scheduled jobs can be run.
|
||||
In case this time interval is missed, for example, due to a power down,
|
||||
then scheduled jobs are not executed that day.
|
||||
.PP
|
||||
The
|
||||
.I RANDOM_DELAY
|
||||
variable denotes the maximum number of minutes that will be added to the
|
||||
delay in minutes variable which is specified for each job. A
|
||||
.I RANDOM_DELAY
|
||||
set to 12 would therefore add, randomly, between 0 and 12 minutes to the
|
||||
delay in minutes for each job in that particular anacrontab. When set to
|
||||
0, no random delay is added.
|
||||
.PP
|
||||
If
|
||||
.I MAILTO
|
||||
is defined (and non-empty), mail is sent to the specified address,
|
||||
otherwise, system user is used.
|
||||
.PP
|
||||
If
|
||||
.I MAILFROM
|
||||
is defined (and non-empty), it is used as the envelope sender address,
|
||||
otherwise, system user is used.
|
||||
.PP
|
||||
(Note: Both
|
||||
.I MAILFROM
|
||||
and
|
||||
.I MAILTO
|
||||
variables are expanded, so setting them as in the following example works as expected: MAILFROM=cron-$USER@cron.com ($USER is replaced by the system user) )
|
||||
.PP
|
||||
.PP
|
||||
Empty lines are either blank lines, line containing white spaces only, or
|
||||
lines with white spaces followed by a '#' followed by an arbitrary
|
||||
comment.
|
||||
.PP
|
||||
You can continue a line onto the next line by adding a '\\' at the end of it.
|
||||
.PP
|
||||
In case you want to disable Anacron, add a line with
|
||||
.I 0anacron
|
||||
which is the name of the script running the Anacron into the
|
||||
.I /etc/cron.hourly/jobs.deny
|
||||
file.
|
||||
.SH EXAMPLE
|
||||
This example shows how to set up an Anacron job similar in functionality to
|
||||
.I /etc/crontab
|
||||
which starts all regular jobs
|
||||
between 6:00 and 8:00
|
||||
.I only.
|
||||
A
|
||||
.I RANDOM_DELAY
|
||||
which can be 30 minutes at the most is specified. Jobs will run
|
||||
serialized in a queue where each job is started only after the previous
|
||||
one is finished.
|
||||
.PP
|
||||
.nf
|
||||
# environment variables
|
||||
SHELL=/bin/sh
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
MAILTO=root
|
||||
RANDOM_DELAY=30
|
||||
# Anacron jobs will start between 6am and 8am.
|
||||
START_HOURS_RANGE=6-8
|
||||
# delay will be 5 minutes + RANDOM_DELAY for cron.daily
|
||||
1 5 cron.daily nice run-parts /etc/cron.daily
|
||||
7 0 cron.weekly nice run-parts /etc/cron.weekly
|
||||
@monthly 0 cron.monthly nice run-parts /etc/cron.monthly
|
||||
.fi
|
||||
.SH "SEE ALSO"
|
||||
.BR anacron (8),
|
||||
.BR crontab (1)
|
||||
.PP
|
||||
The Anacron
|
||||
.I README
|
||||
file.
|
||||
.SH AUTHOR
|
||||
.MT itzur@\:actcom.\:co.\:il
|
||||
Itai Tzur
|
||||
.ME
|
||||
.PP
|
||||
Currently maintained by
|
||||
.MT pasc@\:(debian.\:org|\:redellipse.\:net)
|
||||
Pascal Hakim
|
||||
.ME .
|
||||
.PP
|
||||
For Fedora, maintained by
|
||||
.MT mmaslano@redhat.com
|
||||
Marcela Mašláňová
|
||||
.ME .
|
285
man/cron.8
Normal file
285
man/cron.8
Normal file
@ -0,0 +1,285 @@
|
||||
.\"/* Copyright 1988,1990,1993,1996 by Paul Vixie
|
||||
.\" * All rights reserved
|
||||
.\" */
|
||||
.\"
|
||||
.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
.\" Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" Modified 2010/09/12 by Colin Dean, Durham University IT Service,
|
||||
.\" to add clustering support.
|
||||
.\"
|
||||
.\" $Id: cron.8,v 1.8 2004/01/23 19:03:32 vixie Exp $
|
||||
.\"
|
||||
.TH CRON "8" "2013-09-26" "cronie" "System Administration"
|
||||
.SH NAME
|
||||
crond \- daemon to execute scheduled commands
|
||||
.SH SYNOPSIS
|
||||
.B crond
|
||||
.RB [ -c " | " -h " | " -i " | " -n " | " -p " | " -P " | " -s " | " -m \fP\fI<mail command>\fP ]
|
||||
.br
|
||||
.B crond
|
||||
.B -x
|
||||
.RB [ext,sch,proc,pars,load,misc,test,bit]
|
||||
.br
|
||||
.B crond
|
||||
.B -V
|
||||
.SH DESCRIPTION
|
||||
.I Cron
|
||||
is started from
|
||||
.I /etc/rc.d/init.d
|
||||
or
|
||||
.I /etc/init.d
|
||||
when classical sysvinit scripts are used. In case systemd is enabled, then unit file is installed into
|
||||
.I /lib/systemd/system/crond.service
|
||||
and daemon is started by
|
||||
.I systemctl start crond.service
|
||||
command. It returns immediately, thus, there is no need to need to start it with
|
||||
the '&' parameter.
|
||||
.PP
|
||||
.I Cron
|
||||
searches
|
||||
.I /var/spool/cron
|
||||
for crontab files which are named after accounts in
|
||||
.I /etc/passwd;
|
||||
The found crontabs are loaded into the memory.
|
||||
.I Cron
|
||||
also searches for
|
||||
.I /etc/anacrontab
|
||||
and any files in the
|
||||
.I /etc/cron.d
|
||||
directory, which have a different format (see
|
||||
.BR crontab (5)).
|
||||
.I Cron
|
||||
examines all stored crontabs and checks each job to see if it needs to be
|
||||
run in the current minute. When executing commands, any output is mailed
|
||||
to the owner of the crontab (or to the user specified in the
|
||||
.I MAILTO
|
||||
environment variable in the crontab, if such exists). Any job output can
|
||||
also be sent to syslog by using the
|
||||
.B "\-s"
|
||||
option.
|
||||
.PP
|
||||
There are two ways how changes in crontables are checked. The first
|
||||
method is checking the modtime of a file. The second method is using the
|
||||
inotify support. Using of inotify is logged in the
|
||||
.I /var/log/cron
|
||||
log after the daemon is started. The inotify support checks for changes
|
||||
in all crontables and accesses the hard disk only when a change is
|
||||
detected.
|
||||
.PP
|
||||
When using the modtime option,
|
||||
.I Cron
|
||||
checks its crontables' modtimes every minute to check for any changes and
|
||||
reloads the crontables which have changed. There is no need to restart
|
||||
.I Cron
|
||||
after some of the crontables were modified. The modtime option is also
|
||||
used when inotify can not be initialized.
|
||||
.PP
|
||||
.I Cron
|
||||
checks these files and directories:
|
||||
.TP
|
||||
.IR /etc/crontab
|
||||
system crontab. Nowadays the file is empty by default. Originally it
|
||||
was usually used to run daily, weekly, monthly jobs. By default these
|
||||
jobs are now run through anacron which reads
|
||||
.IR /etc/anacrontab
|
||||
configuration file. See
|
||||
.BR anacrontab (5)
|
||||
for more details.
|
||||
.TP
|
||||
.IR /etc/cron.d/
|
||||
directory that contains system cronjobs stored for different users.
|
||||
.TP
|
||||
.IR /var/spool/cron
|
||||
directory that contains user crontables created by the
|
||||
.IR crontab
|
||||
command.
|
||||
.PP
|
||||
Note that the
|
||||
.BR crontab (1)
|
||||
command updates the modtime of the spool directory whenever it changes a
|
||||
crontab.
|
||||
.PP
|
||||
.SS Daylight Saving Time and other time changes
|
||||
Local time changes of less than three hours, such as those caused by the
|
||||
Daylight Saving Time changes, are handled in a special way. This only
|
||||
applies to jobs that run at a specific time and jobs that run with a
|
||||
granularity greater than one hour. Jobs that run more frequently are
|
||||
scheduled normally.
|
||||
.PP
|
||||
If time was adjusted one hour forward, those jobs that would have run in
|
||||
the interval that has been skipped will be run immediately. Conversely,
|
||||
if time was adjusted backward, running the same job twice is avoided.
|
||||
.PP
|
||||
Time changes of more than 3 hours are considered to be corrections to the
|
||||
clock or the timezone, and the new time is used immediately.
|
||||
.PP
|
||||
It is possible to use different time zones for crontables. See
|
||||
.BR crontab (5)
|
||||
for more information.
|
||||
.SS PAM Access Control
|
||||
.IR Cron
|
||||
supports access control with PAM if the system has PAM installed. For
|
||||
more information, see
|
||||
.BR pam (8).
|
||||
A PAM configuration file for
|
||||
.IR crond
|
||||
is installed in
|
||||
.IR /etc/pam.d/crond .
|
||||
The daemon loads the PAM environment from the pam_env module. This can
|
||||
be overridden by defining specific settings in the appropriate crontab
|
||||
file.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
.B "\-h"
|
||||
Prints a help message and exits.
|
||||
.TP
|
||||
.B "\-i"
|
||||
Disables inotify support.
|
||||
.TP
|
||||
.B "\-m"
|
||||
This option allows you to specify a shell command to use for sending
|
||||
.I Cron
|
||||
mail output instead of using
|
||||
.BR sendmail (8)
|
||||
This command must accept a fully formatted mail message (with headers) on
|
||||
standard input and send it as a mail message to the recipients specified
|
||||
in the mail headers. Specifying the string
|
||||
.I "off"
|
||||
(i.e., crond -m off)
|
||||
will disable the sending of mail.
|
||||
.TP
|
||||
.B "\-n"
|
||||
Tells the daemon to run in the foreground. This can be useful when
|
||||
starting it out of init. With this option is needed to change pam setting.
|
||||
.I /etc/pam.d/crond
|
||||
must not enable
|
||||
.I pam_loginuid.so
|
||||
module.
|
||||
.TP
|
||||
.B "\-f"
|
||||
the same as -n, consistent with other crond implementations.
|
||||
.TP
|
||||
.B "\-p"
|
||||
Allows
|
||||
.I Cron
|
||||
to accept any user set crontables.
|
||||
.TP
|
||||
.B "\-P"
|
||||
Don't set PATH. PATH is instead inherited from the environment.
|
||||
.TP
|
||||
.B "\-c"
|
||||
This option enables clustering support, as described below.
|
||||
.TP
|
||||
.B "\-s"
|
||||
This option will direct
|
||||
.I Cron
|
||||
to send the job output to the system log using
|
||||
.BR syslog (3).
|
||||
This is useful if your system does not have
|
||||
.BR sendmail (8),
|
||||
installed or if mail is disabled.
|
||||
.TP
|
||||
.B "\-x"
|
||||
This option allows you to set debug flags.
|
||||
.TP
|
||||
.B "\-V"
|
||||
Print version and exit.
|
||||
.SH SIGNALS
|
||||
When the
|
||||
.I SIGHUP
|
||||
is received, the
|
||||
.I Cron
|
||||
daemon will close and reopen its log file. This proves to be useful in
|
||||
scripts which rotate and age log files. Naturally, this is not relevant
|
||||
if
|
||||
.I Cron
|
||||
was built to use
|
||||
.IR syslog (3).
|
||||
.SH CLUSTERING SUPPORT
|
||||
In this version of
|
||||
.IR Cron
|
||||
it is possible to use a network-mounted shared
|
||||
.I /var/spool/cron
|
||||
across a cluster of hosts and specify that only one of the hosts should
|
||||
run the crontab jobs in this directory at any one time. This is done by
|
||||
starting
|
||||
.I Cron
|
||||
with the
|
||||
.B \-c
|
||||
option, and have the
|
||||
.I /var/spool/cron/.cron.hostname
|
||||
file contain just one line, which represents the hostname of whichever
|
||||
host in the cluster should run the jobs. If this file does not exist, or
|
||||
the hostname in it does not match that returned by
|
||||
.BR gethostname (2),
|
||||
then all crontab files in this directory are ignored. This has no effect
|
||||
on cron jobs specified in the
|
||||
.I /etc/crontab
|
||||
file or on files in the
|
||||
.I /etc/cron.d
|
||||
directory. These files are always run and considered host-specific.
|
||||
.PP
|
||||
Rather than editing
|
||||
.I /var/spool/cron/.cron.hostname
|
||||
directly, use the
|
||||
.B \-n
|
||||
option of
|
||||
.BR crontab (1)
|
||||
to specify the host.
|
||||
.PP
|
||||
You should ensure that all hosts in a cluster, and the file server from
|
||||
which they mount the shared crontab directory, have closely synchronised
|
||||
clocks, e.g., using
|
||||
.BR ntpd (8),
|
||||
otherwise the results will be very unpredictable.
|
||||
.PP
|
||||
Using cluster sharing automatically disables inotify support, because
|
||||
inotify cannot be relied on with network-mounted shared file systems.
|
||||
.SH CAVEATS
|
||||
All
|
||||
.BR crontab
|
||||
files have to be regular files or symlinks to regular files, they must
|
||||
not be executable or writable for anyone else but the owner. This
|
||||
requirement can be overridden by using the
|
||||
.B \-p
|
||||
option on the crond command line. If inotify support is in use, changes
|
||||
in the symlinked crontabs are not automatically noticed by the cron
|
||||
daemon. The cron daemon must receive a SIGHUP signal to reload the
|
||||
crontabs. This is a limitation of the inotify API.
|
||||
.PP
|
||||
The syslog output will be used instead of mail, when sendmail is not
|
||||
installed.
|
||||
.SH "SEE ALSO"
|
||||
.BR crontab (1),
|
||||
.BR crontab (5),
|
||||
.BR inotify (7),
|
||||
.BR pam (8)
|
||||
.SH AUTHOR
|
||||
.MT vixie@isc.org
|
||||
Paul Vixie
|
||||
.ME
|
||||
.br
|
||||
.MT mmaslano@redhat.com
|
||||
Marcela Mašláňová
|
||||
.ME
|
||||
.br
|
||||
.MT colin@colin-dean.org
|
||||
Colin Dean
|
||||
.ME
|
||||
.br
|
||||
.MT tmraz@fedoraproject.org
|
||||
Tomáš Mráz
|
||||
.ME
|
1
man/crond.8
Normal file
1
man/crond.8
Normal file
@ -0,0 +1 @@
|
||||
.so man8/cron.8
|
86
man/cronnext.1
Normal file
86
man/cronnext.1
Normal file
@ -0,0 +1,86 @@
|
||||
.TH CRONNEXT 1 "2017-06-11" "cronie" "User Commands"
|
||||
.SH NAME
|
||||
cronnext \- time of next job cron will execute
|
||||
.SH SYNOPSIS
|
||||
.TP 9
|
||||
.B cronnext
|
||||
[\fB-i \fIusers\fR] [\fB-e \fIusers\fR] [\fB-s\fR]
|
||||
[\fB-a\fR]
|
||||
[\fB-t \fItime\fR] [\fB-q \fItime\fR] [\fB-j \fIcommand\fR]
|
||||
[\fB-l\fR] [\fB-c\fR] [\fB-f\fR] [\fB-h\fR] [\fB-V\fR]
|
||||
[file]...
|
||||
.SH DESCRIPTION
|
||||
Determine the time cron will execute the next job. Without arguments, it
|
||||
prints that time considering all crontabs, in number of seconds since the
|
||||
Epoch, rounded to the minute. This number can be converted into other formats
|
||||
using
|
||||
.BR date (1),
|
||||
like
|
||||
.B date --date @43243254
|
||||
|
||||
The file arguments are optional. If provided,
|
||||
.I cronnext
|
||||
uses them as crontabs instead of the ones installed in the system.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI "\-i " user,user,user,...
|
||||
Consider only the crontabs of the specified users. Use
|
||||
.B *system*
|
||||
for the system crontab.
|
||||
.TP
|
||||
.BI "\-e " user,user,user,...
|
||||
Do not consider the crontabs of the specified users.
|
||||
.TP
|
||||
.B \-s
|
||||
Do not consider the system crontab, usually the
|
||||
.I /etc/crontab
|
||||
file. The system crontab usually contains the hourly, daily, weekly and
|
||||
montly crontabs, which might be better dealt with
|
||||
.BR anacron (8).
|
||||
.TP
|
||||
.BI \-a
|
||||
Use the crontabs installed in the system in addition to the ones passed as
|
||||
file arguments. This is implicit if no file is passed.
|
||||
.TP
|
||||
.BI "\-t " time
|
||||
Determine the next job from this time, instead of now. The time is
|
||||
expressed in number of seconds since the Epoch, as obtained for example by
|
||||
.BR "date +%s --date \(dqnow + 2 hours\(dq" ,
|
||||
and is internally rounded to the minute.
|
||||
.TP
|
||||
.BI "\-q " time
|
||||
Do not check jobs over this time, expressed in the same way as in option
|
||||
.BR -t .
|
||||
.TP
|
||||
.BI "\-j " command
|
||||
Only look for jobs that contain \fIcommand\fP as a substring.
|
||||
.TP
|
||||
.B \-l
|
||||
Print the whole entries of the jobs that are the next to be executed by cron.
|
||||
The default is to only print their next time of execution.
|
||||
.TP
|
||||
.B \-c
|
||||
Print every entry in every crontab with the next time it is executed.
|
||||
.TP
|
||||
.B \-f
|
||||
Print all jobs that are executed in the given interval. Requires option
|
||||
\fB-q\fR.
|
||||
.TP
|
||||
.B \-h
|
||||
Print usage output and exit.
|
||||
.TP
|
||||
.B \-V
|
||||
Print version and exit.
|
||||
.SH AUTHOR
|
||||
.MT sgerwk@aol.com
|
||||
Marco Migliori
|
||||
.ME
|
||||
.SH SEE ALSO
|
||||
.BR cron (8),
|
||||
.BR cron (1),
|
||||
.BR crontab (5),
|
||||
.BR crontab (1),
|
||||
.BR anacron (8),
|
||||
.BR anacrontab (5),
|
||||
.BR atq (1),
|
||||
.BR date (1)
|
251
man/crontab.1
Normal file
251
man/crontab.1
Normal file
@ -0,0 +1,251 @@
|
||||
.\"/* Copyright 1988,1990,1993 by Paul Vixie
|
||||
.\" * All rights reserved
|
||||
.\" */
|
||||
.\"
|
||||
.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
.\" Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" Modified 2010/09/12 by Colin Dean, Durham University IT Service,
|
||||
.\" to add clustering support.
|
||||
.\"
|
||||
.\" $Id: crontab.1,v 1.7 2004/01/23 19:03:32 vixie Exp $
|
||||
.\"
|
||||
.TH CRONTAB 1 "2019-10-29" "cronie" "User Commands"
|
||||
.SH NAME
|
||||
crontab \- maintains crontab files for individual users
|
||||
.SH SYNOPSIS
|
||||
.B crontab
|
||||
.RB [ -u
|
||||
.IR user ]
|
||||
.RI < "file"
|
||||
.RB | \ - >
|
||||
.br
|
||||
.B crontab
|
||||
.RB [ -T ]
|
||||
.RI < "file"
|
||||
.RB | \ - >
|
||||
.br
|
||||
.B crontab
|
||||
.RB [ -u
|
||||
.IR user ]
|
||||
.RB < -l " | " -r " | " -e >\ [ -i ]
|
||||
.RB [ -s ]
|
||||
.br
|
||||
.B crontab
|
||||
.BR -n \ [
|
||||
.IR "hostname " ]
|
||||
.br
|
||||
.B crontab
|
||||
.BR -c
|
||||
.br
|
||||
.B crontab
|
||||
.BR -V
|
||||
.SH DESCRIPTION
|
||||
.I Crontab
|
||||
is the program used to install a crontab table
|
||||
.IR file ,
|
||||
remove or list the existing tables used to serve the
|
||||
.BR cron (8)
|
||||
daemon. Each user can have their own crontab, and though these are files
|
||||
in
|
||||
.IR /var/spool/ ,
|
||||
they are not intended to be edited directly. For SELinux in MLS mode,
|
||||
you can define more crontabs for each range. For more information, see
|
||||
.BR selinux (8).
|
||||
.PP
|
||||
In this version of
|
||||
.IR Cron
|
||||
it is possible to use a network-mounted shared
|
||||
.I /var/spool/cron
|
||||
across a cluster of hosts and specify that only one of the hosts should
|
||||
run the crontab jobs in the particular directory at any one time. You
|
||||
may also use
|
||||
.BR crontab
|
||||
from any of these hosts to edit the same shared set of crontab files, and
|
||||
to set and query which host should run the crontab jobs.
|
||||
.PP
|
||||
Scheduling cron jobs with
|
||||
.BR crontab
|
||||
can be allowed or disallowed for different users. For this purpose, use the
|
||||
.I cron.allow
|
||||
and
|
||||
.I cron.deny
|
||||
files. If the
|
||||
.I cron.allow
|
||||
file exists, a user must be listed in it to be allowed to use
|
||||
.BR crontab .
|
||||
If the
|
||||
.I cron.allow
|
||||
file does not exist but the
|
||||
.I cron.deny
|
||||
file does exist, then a user must
|
||||
.I not
|
||||
be listed in the
|
||||
.I cron.deny
|
||||
file in order to use
|
||||
.BR crontab.
|
||||
If neither of these files exist, then only the super user is allowed to use
|
||||
.BR crontab .
|
||||
.PP
|
||||
Another way to restrict the scheduling of cron jobs beyond
|
||||
.BR crontab
|
||||
is to use PAM authentication in
|
||||
.I /etc/security/access.conf
|
||||
to set up users, which are allowed or disallowed to use
|
||||
.BR crontab
|
||||
or modify system cron jobs in the
|
||||
.IR /etc/cron.d/
|
||||
directory.
|
||||
.PP
|
||||
The temporary directory can be set in an environment variable. If it is
|
||||
not set by the user, the
|
||||
.I /tmp
|
||||
directory is used.
|
||||
.PP
|
||||
When listing a crontab on a terminal the output will be colorized unless
|
||||
an environment variable
|
||||
.I NO_COLOR
|
||||
is set.
|
||||
.PP
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
.B "\-u"
|
||||
Specifies the name of the user whose crontab is to be modified. If this
|
||||
option is not used,
|
||||
.BR crontab
|
||||
examines "your" crontab, i.e., the crontab of the person executing the
|
||||
command. If no crontab exists for a particular user, it is created for
|
||||
them the first time the
|
||||
.B crontab -u
|
||||
command is used under their username.
|
||||
.TP
|
||||
.B "\-T"
|
||||
Test the crontab file syntax without installing it.
|
||||
Once an issue is found, the validation is interrupted, so this will not return all the existing issues at the same execution.
|
||||
.TP
|
||||
.B "\-l"
|
||||
Displays the current crontab on standard output.
|
||||
.TP
|
||||
.B "\-r"
|
||||
Removes the current crontab.
|
||||
.TP
|
||||
.B "\-e"
|
||||
Edits the current crontab using the editor specified by the
|
||||
.I VISUAL
|
||||
or
|
||||
.I EDITOR
|
||||
environment variables. After you exit from the editor, the modified
|
||||
crontab will be installed automatically.
|
||||
.TP
|
||||
.B "\-i"
|
||||
This option modifies the
|
||||
.B "\-r"
|
||||
option to prompt the user for a 'y/Y' response before actually removing
|
||||
the crontab.
|
||||
.TP
|
||||
.B "\-s"
|
||||
Appends the current SELinux security context string as an MLS_LEVEL
|
||||
setting to the crontab file before editing / replacement occurs - see the
|
||||
documentation of MLS_LEVEL in
|
||||
.BR crontab (5).
|
||||
.TP
|
||||
.B "\-n"
|
||||
This option is relevant only if
|
||||
.BR cron (8)
|
||||
was started with the
|
||||
.B \-c
|
||||
option, to enable clustering support. It is used to set the host in the
|
||||
cluster which should run the jobs specified in the crontab files in the
|
||||
.I /var/spool/cron
|
||||
directory. If a hostname is supplied, the host whose hostname returned
|
||||
by
|
||||
.BR gethostname (2)
|
||||
matches the supplied hostname, will be selected to run the selected cron jobs subsequently. If there
|
||||
is no host in the cluster matching the supplied hostname, or you explicitly specify
|
||||
an empty hostname, then the selected jobs will not be run at all. If the hostname
|
||||
is omitted, the name of the local host returned by
|
||||
.BR gethostname (2)
|
||||
is used. Using this option has no effect on the
|
||||
.I /etc/crontab
|
||||
file and the files in the
|
||||
.I /etc/cron.d
|
||||
directory, which are always run, and considered host-specific. For more
|
||||
information on clustering support, see
|
||||
.BR cron (8).
|
||||
.TP
|
||||
.B "\-c"
|
||||
This option is only relevant if
|
||||
.BR cron (8)
|
||||
was started with the
|
||||
.B \-c
|
||||
option, to enable clustering support. It is used to query which host in
|
||||
the cluster is currently set to run the jobs specified in the crontab
|
||||
files in the directory
|
||||
.I /var/spool/cron
|
||||
, as set using the
|
||||
.B \-n
|
||||
option.
|
||||
.TP
|
||||
.B "\-V"
|
||||
Print version and exit.
|
||||
.SH CAVEATS
|
||||
The files
|
||||
.I cron.allow
|
||||
and
|
||||
.I cron.deny
|
||||
cannot be used to restrict the execution of cron jobs; they only restrict the
|
||||
use of
|
||||
.BR crontab .
|
||||
In particular, restricting access to
|
||||
.BR crontab
|
||||
has no effect on an existing
|
||||
.I crontab
|
||||
of a user. Its jobs will continue to be executed until the crontab is removed.
|
||||
.PP
|
||||
The files
|
||||
.I cron.allow
|
||||
and
|
||||
.I cron.deny
|
||||
must be readable by the user invoking
|
||||
.BR crontab .
|
||||
If this is not the case, then they are treated as non-existent.
|
||||
.SH "SEE ALSO"
|
||||
.BR crontab (5),
|
||||
.BR cron (8)
|
||||
.SH FILES
|
||||
.nf
|
||||
/etc/cron.allow
|
||||
/etc/cron.deny
|
||||
.fi
|
||||
.SH STANDARDS
|
||||
The
|
||||
.I crontab
|
||||
command conforms to IEEE Std1003.2-1992 (``POSIX'') with one exception:
|
||||
For replacing the current crontab with data from standard input the
|
||||
.B \-
|
||||
has to be specified on the command line if the standard input is a TTY.
|
||||
This new command syntax differs from previous versions of Vixie Cron,
|
||||
as well as from the classic SVR3 syntax.
|
||||
.SH DIAGNOSTICS
|
||||
An informative usage message appears if you run a crontab with a faulty
|
||||
command defined in it.
|
||||
.SH AUTHOR
|
||||
.MT vixie@isc.org
|
||||
Paul Vixie
|
||||
.ME
|
||||
.br
|
||||
.MT colin@colin-dean.org
|
||||
Colin Dean
|
||||
.ME
|
357
man/crontab.5
Normal file
357
man/crontab.5
Normal file
@ -0,0 +1,357 @@
|
||||
.\"/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
.\" * All rights reserved
|
||||
.\" */
|
||||
.\"
|
||||
.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
.\" Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.\" $Id: crontab.5,v 1.6 2004/01/23 19:03:33 vixie Exp $
|
||||
.\"
|
||||
.TH CRONTAB 5 2012-11-22 "cronie" "File Formats"
|
||||
.SH NAME
|
||||
crontab \- files used to schedule the execution of programs
|
||||
.SH DESCRIPTION
|
||||
A
|
||||
.I crontab
|
||||
file contains instructions for the
|
||||
.BR cron (8)
|
||||
daemon in the following simplified manner: "run this command at this time
|
||||
on this date". Each user can define their own crontab. Commands defined
|
||||
in any given crontab are executed under the user who owns that particular
|
||||
crontab. Uucp and News usually have their own crontabs, eliminating the
|
||||
need for explicitly running
|
||||
.BR su (1)
|
||||
as part of a cron command.
|
||||
.PP
|
||||
Blank lines, leading spaces, and tabs are ignored. Lines whose first
|
||||
non-white space character is a pound-sign (#) are comments, and are not
|
||||
processed. Note that comments are not allowed on the same line as cron
|
||||
commands, since they are considered a part of the command. Similarly,
|
||||
comments are not allowed on the same line as environment variable
|
||||
settings.
|
||||
.PP
|
||||
An active line in a crontab is either an environment setting or a cron
|
||||
command. An environment setting is of the form:
|
||||
.PP
|
||||
name = value
|
||||
.PP
|
||||
where the white spaces around the equal-sign (=) are optional, and any
|
||||
subsequent non-leading white spaces in
|
||||
.I value
|
||||
is a part of the value assigned to
|
||||
.IR name .
|
||||
The
|
||||
.I value
|
||||
string may be placed in quotes (single or double, but matching) to
|
||||
preserve leading or trailing white spaces.
|
||||
.PP
|
||||
Several environment variables are set up automatically by the
|
||||
.BR cron (8)
|
||||
daemon.
|
||||
.I SHELL
|
||||
is set to /bin/sh, and
|
||||
.I LOGNAME
|
||||
and
|
||||
.I HOME
|
||||
are set from the /etc/passwd line of the crontab\'s owner.
|
||||
.I HOME
|
||||
and
|
||||
.I SHELL
|
||||
can be overridden by settings in the crontab; LOGNAME can not.
|
||||
.PP
|
||||
(Note: the
|
||||
.I LOGNAME
|
||||
variable is sometimes called
|
||||
.I USER
|
||||
on BSD systems and is also automatically set).
|
||||
.PP
|
||||
In addition to
|
||||
.IR LOGNAME ,
|
||||
.IR HOME ,
|
||||
and
|
||||
.IR SHELL ,
|
||||
.BR cron (8)
|
||||
looks at the
|
||||
.I MAILTO
|
||||
variable if a mail needs to be send as a result of running any commands
|
||||
in that particular crontab. If
|
||||
.I MAILTO
|
||||
is defined (and non-empty), mail is sent to the specified address. If
|
||||
.I MAILTO
|
||||
is defined but empty
|
||||
.RI ( MAILTO="" ),
|
||||
no mail is sent. Otherwise, mail is sent to the owner of the crontab.
|
||||
This option is useful if you decide to use /bin/mail instead of
|
||||
/usr/lib/sendmail as your mailer. Note that /bin/mail does not provide
|
||||
aliasing and UUCP usually does not read its mail. If
|
||||
.I MAILFROM
|
||||
is defined (and non-empty), it is used as the envelope sender address,
|
||||
otherwise, ``root'' is used.
|
||||
.PP
|
||||
(Note: Both
|
||||
.I MAILFROM
|
||||
and
|
||||
.I MAILTO
|
||||
variables are expanded, so setting them as in the following example works as expected: MAILFROM=cron-$USER@cron.com ($USER is replaced by the system user) )
|
||||
.PP
|
||||
By default, cron sends a mail using the 'Content-Type:' header
|
||||
of 'text/plain' with the 'charset=' parameter set to the 'charmap/codeset'
|
||||
of the locale in which
|
||||
.BR crond (8)
|
||||
is started up, i.e., either the default system locale, if no LC_*
|
||||
environment variables are set, or the locale specified by the LC_*
|
||||
environment variables (see
|
||||
.BR locale (7)).
|
||||
Different character encodings can be used for mailing cron job outputs by
|
||||
setting the
|
||||
.I CONTENT_TYPE
|
||||
and
|
||||
.I CONTENT_TRANSFER_ENCODING
|
||||
variables in a crontab to the correct values of the mail headers of those
|
||||
names.
|
||||
.PP
|
||||
The
|
||||
.I CRON_TZ
|
||||
variable specifies the time zone specific for the cron table. The user
|
||||
should enter a time according to the specified time zone into the table.
|
||||
The time used for writing into a log file is taken from the local time
|
||||
zone, where the daemon is running.
|
||||
.PP
|
||||
The
|
||||
.I MLS_LEVEL
|
||||
environment variable provides support for multiple per-job SELinux
|
||||
security contexts in the same crontab. By default, cron jobs execute
|
||||
with the default SELinux security context of the user that created the
|
||||
crontab file. When using multiple security levels and roles, this may
|
||||
not be sufficient, because the same user may be running in different
|
||||
roles or in different security levels. For more information about roles
|
||||
and SELinux MLS/MCS, see
|
||||
.BR selinux (8)
|
||||
and the crontab example mentioned later on in this text. You can set the
|
||||
.I MLS_LEVEL
|
||||
variable to the SELinux security context string specifying the particular
|
||||
SELinux security context in which you want jobs to be run.
|
||||
.B crond
|
||||
will then set the execution context of those jobs that meet the
|
||||
specifications of the particular security context. For more information,
|
||||
see
|
||||
.BR crontab (1)\ -s\ option.
|
||||
.PP
|
||||
The
|
||||
.I RANDOM_DELAY
|
||||
variable allows delaying job startups by random amount of minutes with
|
||||
upper limit specified by the variable. The random scaling factor is
|
||||
determined during the cron daemon startup so it remains constant for
|
||||
the whole run time of the daemon.
|
||||
.PP
|
||||
The format of a cron command is similar to the V7 standard, with a number
|
||||
of upward-compatible extensions. Each line has five time-and-date fields
|
||||
followed by a
|
||||
.BR user name
|
||||
(if this is the
|
||||
.BR system
|
||||
crontab file), and followed by a command. Commands are executed by
|
||||
.BR cron (8)
|
||||
when the 'minute', 'hour', and 'month of the year' fields match the
|
||||
current time,
|
||||
.I and
|
||||
at least one of the two 'day' fields ('day of month', or 'day of week')
|
||||
match the current time (see "Note" below).
|
||||
.PP
|
||||
Note that this means that non-existent times, such as the "missing hours"
|
||||
during the daylight savings time conversion, will never match, causing
|
||||
jobs scheduled during the "missing times" not to be run. Similarly,
|
||||
times that occur more than once (again, during the daylight savings time
|
||||
conversion) will cause matching jobs to be run twice.
|
||||
.PP
|
||||
.BR cron (8)
|
||||
examines cron entries every minute.
|
||||
.PP
|
||||
The time and date fields are:
|
||||
.IP
|
||||
.ta 1.5i
|
||||
field allowed values
|
||||
.br
|
||||
----- --------------
|
||||
.br
|
||||
minute 0-59
|
||||
.br
|
||||
hour 0-23
|
||||
.br
|
||||
day of month 1-31
|
||||
.br
|
||||
month 1-12 (or names, see below)
|
||||
.br
|
||||
day of week 0-7 (0 or 7 is Sunday, or use names)
|
||||
.br
|
||||
.PP
|
||||
A field may contain an asterisk (*), which always stands for
|
||||
"first\-last".
|
||||
.PP
|
||||
Ranges of numbers are allowed. Ranges are two numbers separated with a
|
||||
hyphen. The specified range is inclusive. For example, 8-11 for
|
||||
an 'hours' entry specifies execution at hours 8, 9, 10, and 11. The first
|
||||
number must be less than or equal to the second one.
|
||||
.PP
|
||||
Randomization of the execution time within a range can be used.
|
||||
A random number within a range specified as two numbers separated with
|
||||
a tilde is picked. The specified range is inclusive.
|
||||
For example, 6~15 for a 'minutes' entry picks a random minute
|
||||
within 6 to 15 range. The random number is picked when crontab file is parsed.
|
||||
The first number must be less than or equal to the second one. You might omit
|
||||
one or both of the numbers specifying the range. For example, ~ for a 'minutes'
|
||||
entry picks a random minute within 0 to 59 range.
|
||||
.PP
|
||||
Lists are allowed. A list is a set of numbers (or ranges) separated by
|
||||
commas. Examples: "1,2,5,9", "0-4,8-12".
|
||||
.PP
|
||||
Step values can be used in conjunction with ranges. Following a range
|
||||
with "/<number>" specifies skips of the number's value through the range.
|
||||
For example, "0-23/2" can be used in the 'hours' field to specify command
|
||||
execution for every other hour (the alternative in the V7 standard is
|
||||
"0,\:2,\:4,\:6,\:8,\:10,\:12,\:14,\:16,\:18,\:20,\:22"). Step values are
|
||||
also permitted after an asterisk, so if specifying a job to be run every
|
||||
two hours, you can use "*/2".
|
||||
.PP
|
||||
Names can also be used for the 'month' and 'day of week' fields. Use the
|
||||
first three letters of the particular day or month (case does not
|
||||
matter). Ranges and lists of names are allowed. Examples: "mon,wed,fri",
|
||||
"jan-mar".
|
||||
.PP
|
||||
If the UID of the owner is 0 (root), the first character of a crontab
|
||||
entry can be "-" character. This will prevent cron from writing a syslog
|
||||
message about the command being executed.
|
||||
.PP
|
||||
The "sixth" field (the rest of the line) specifies the command to be run.
|
||||
The entire command portion of the line, up to a newline or a "%"
|
||||
character, will be executed by /bin/sh or by the shell specified in the
|
||||
SHELL variable of the cronfile. A "%" character in the command, unless
|
||||
escaped with a backslash (\\), will be changed into newline characters,
|
||||
and all data after the first % will be sent to the command as standard
|
||||
input.
|
||||
.PP
|
||||
Note: The day of a command's execution can be specified in the following
|
||||
two fields \(em 'day of month', and 'day of week'. If both fields are
|
||||
restricted (i.e., do not contain the "*" character), the command will be
|
||||
run when
|
||||
.I either
|
||||
field matches the current time. For example,
|
||||
.br
|
||||
"30 4 1,15 * 5" would cause a command to be run at 4:30 am on the 1st and
|
||||
15th of each month, plus every Friday.
|
||||
.PP
|
||||
A crontab file syntax can be tested before an install using the -T option. See
|
||||
.BR crontab (1)
|
||||
for details.
|
||||
.SH EXAMPLE CRON FILE
|
||||
.nf
|
||||
# use /bin/sh to run commands, no matter what /etc/passwd says
|
||||
SHELL=/bin/sh
|
||||
# mail any output to `paul', no matter whose crontab this is
|
||||
MAILTO=paul
|
||||
#
|
||||
CRON_TZ=Japan
|
||||
# run five minutes after midnight, every day
|
||||
5 0 * * * $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
|
||||
# run at 2:15pm on the first of every month -- output mailed to paul
|
||||
15 14 1 * * $HOME/bin/monthly
|
||||
# run at 10 pm on weekdays, annoy Joe
|
||||
0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
|
||||
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
|
||||
5 4 * * sun echo "run at 5 after 4 every sunday"
|
||||
.fi
|
||||
.SH Jobs in /etc/cron.d/
|
||||
The jobs in
|
||||
.I cron.d
|
||||
and
|
||||
.I /etc/crontab
|
||||
are system jobs, which are used usually for more than one user, thus,
|
||||
additionally the username is needed. MAILTO on the first line is
|
||||
optional.
|
||||
.SH EXAMPLE OF A JOB IN /etc/cron.d/job
|
||||
.nf
|
||||
#login as root
|
||||
#create job with preferred editor (e.g. vim)
|
||||
MAILTO=root
|
||||
* * * * * root touch /tmp/file
|
||||
.fi
|
||||
.SH SELinux with multi level security (MLS)
|
||||
In a crontab, it is important to specify a security level by
|
||||
.I crontab \-s
|
||||
or specifying the required level on the first line of the crontab. Each
|
||||
level is specified in
|
||||
.IR /etc/selinux/targeted/seusers .
|
||||
When using crontab in the MLS mode, it is especially important to:
|
||||
.br
|
||||
- check/change the actual role,
|
||||
.br
|
||||
- set correct
|
||||
.I role for
|
||||
.IR directory ,
|
||||
which is used for input/output.
|
||||
.SH EXAMPLE FOR SELINUX MLS
|
||||
.nf
|
||||
# login as root
|
||||
newrole -r sysadm_r
|
||||
mkdir /tmp/SystemHigh
|
||||
chcon -l SystemHigh /tmp/SystemHigh
|
||||
crontab -e
|
||||
# write in crontab file
|
||||
MLS_LEVEL=SystemHigh
|
||||
0-59 * * * * id -Z > /tmp/SystemHigh/crontest
|
||||
.fi
|
||||
.SH FILES
|
||||
.I /etc/crontab
|
||||
main system crontab file.
|
||||
.I /var/spool/cron/
|
||||
a directory for storing crontabs defined by users.
|
||||
.I /etc/cron.d/
|
||||
a directory for storing system crontabs.
|
||||
.SH "SEE ALSO"
|
||||
.BR cron (8),
|
||||
.BR crontab (1)
|
||||
.SH EXTENSIONS
|
||||
These special time specification "nicknames" which replace the 5 initial
|
||||
time and date fields, and are prefixed with the '@' character, are
|
||||
supported:
|
||||
.PP
|
||||
.nf
|
||||
@reboot : Run once after reboot.
|
||||
@yearly : Run once a year, ie. "0 0 1 1 *".
|
||||
@annually : Run once a year, ie. "0 0 1 1 *".
|
||||
@monthly : Run once a month, ie. "0 0 1 * *".
|
||||
@weekly : Run once a week, ie. "0 0 * * 0".
|
||||
@daily : Run once a day, ie. "0 0 * * *".
|
||||
@hourly : Run once an hour, ie. "0 * * * *".
|
||||
.fi
|
||||
.SH CAVEATS
|
||||
.BR crontab
|
||||
files have to be regular files or symlinks to regular files, they must
|
||||
not be executable or writable for anyone else but the owner. This
|
||||
requirement can be overridden by using the
|
||||
.B \-p
|
||||
option on the crond command line. If inotify support is in use, changes
|
||||
in the symlinked crontabs are not automatically noticed by the cron
|
||||
daemon. The cron daemon must receive a SIGHUP signal to reload the
|
||||
crontabs. This is a limitation of the inotify API.
|
||||
.PP
|
||||
cron requires that each entry in a crontab end in a newline character. If the
|
||||
last entry in a crontab is missing a newline (i.e.\& terminated by EOF),
|
||||
cron will consider the crontab (at least partially) broken.
|
||||
A warning will be written to syslog.
|
||||
.SH AUTHOR
|
||||
.MT vixie@isc.org
|
||||
Paul Vixie
|
||||
.ME
|
215
missing
Executable file
215
missing
Executable file
@ -0,0 +1,215 @@
|
||||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1996-2018 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=https://www.perl.org/
|
||||
flex_URL=https://github.com/westes/flex
|
||||
gnu_software_URL=https://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
376
obstack/obstack.c
Normal file
376
obstack/obstack.c
Normal file
@ -0,0 +1,376 @@
|
||||
/* obstack.c - subroutines used implicitly by object stack macros
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <obstack.h>
|
||||
#else
|
||||
# include <config.h>
|
||||
# include "obstack.h"
|
||||
#endif
|
||||
|
||||
/* NOTE BEFORE MODIFYING THIS FILE: _OBSTACK_INTERFACE_VERSION in
|
||||
obstack.h must be incremented whenever callers compiled using an old
|
||||
obstack.h can no longer properly call the functions in this file. */
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself, and the installed library
|
||||
supports the same library interface we do. This code is part of the GNU
|
||||
C Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand 'configure --with-gnu-libc' and omit the object
|
||||
files, it is simpler to just do this in the source for each such file. */
|
||||
#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
|
||||
# include <gnu-versions.h>
|
||||
# if (_GNU_OBSTACK_INTERFACE_VERSION == _OBSTACK_INTERFACE_VERSION \
|
||||
|| (_GNU_OBSTACK_INTERFACE_VERSION == 1 \
|
||||
&& _OBSTACK_INTERFACE_VERSION == 2 \
|
||||
&& defined SIZEOF_INT && defined SIZEOF_SIZE_T \
|
||||
&& SIZEOF_INT == SIZEOF_SIZE_T))
|
||||
# define _OBSTACK_ELIDE_CODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _OBSTACK_ELIDE_CODE
|
||||
/* If GCC, or if an oddball (testing?) host that #defines __alignof__,
|
||||
use the already-supplied __alignof__. Otherwise, this must be Gnulib
|
||||
(as glibc assumes GCC); defer to Gnulib's alignof_type. */
|
||||
# if !defined __GNUC__ && !defined __IBM__ALIGNOF__ && !defined __alignof__
|
||||
# if defined __cplusplus
|
||||
template <class type> struct alignof_helper { char __slot1; type __slot2; };
|
||||
# define __alignof__(type) offsetof (alignof_helper<type>, __slot2)
|
||||
# else
|
||||
# define __alignof__(type) \
|
||||
offsetof (struct { char __slot1; type __slot2; }, __slot2)
|
||||
# endif
|
||||
# endif
|
||||
# include <stdlib.h>
|
||||
# include <stdint.h>
|
||||
|
||||
# ifndef MAX
|
||||
# define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
# endif
|
||||
|
||||
/* Determine default alignment. */
|
||||
|
||||
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
|
||||
But in fact it might be less smart and round addresses to as much as
|
||||
DEFAULT_ROUNDING. So we prepare for it to do that.
|
||||
|
||||
DEFAULT_ALIGNMENT cannot be an enum constant; see gnulib's alignof.h. */
|
||||
#define DEFAULT_ALIGNMENT MAX (__alignof__ (long double), \
|
||||
MAX (__alignof__ (uintmax_t), \
|
||||
__alignof__ (void *)))
|
||||
#define DEFAULT_ROUNDING MAX (sizeof (long double), \
|
||||
MAX (sizeof (uintmax_t), \
|
||||
sizeof (void *)))
|
||||
|
||||
/* Call functions with either the traditional malloc/free calling
|
||||
interface, or the mmalloc/mfree interface (that adds an extra first
|
||||
argument), based on the value of use_extra_arg. */
|
||||
|
||||
static void *
|
||||
call_chunkfun (struct obstack *h, size_t size)
|
||||
{
|
||||
if (h->use_extra_arg)
|
||||
return h->chunkfun.extra (h->extra_arg, size);
|
||||
else
|
||||
return h->chunkfun.plain (size);
|
||||
}
|
||||
|
||||
static void
|
||||
call_freefun (struct obstack *h, void *old_chunk)
|
||||
{
|
||||
if (h->use_extra_arg)
|
||||
h->freefun.extra (h->extra_arg, old_chunk);
|
||||
else
|
||||
h->freefun.plain (old_chunk);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
|
||||
Objects start on multiples of ALIGNMENT (0 means use default).
|
||||
|
||||
Return nonzero if successful, calls obstack_alloc_failed_handler if
|
||||
allocation fails. */
|
||||
|
||||
static int
|
||||
_obstack_begin_worker (struct obstack *h,
|
||||
_OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment)
|
||||
{
|
||||
struct _obstack_chunk *chunk; /* points to new chunk */
|
||||
|
||||
if (alignment == 0)
|
||||
alignment = DEFAULT_ALIGNMENT;
|
||||
if (size == 0)
|
||||
/* Default size is what GNU malloc can fit in a 4096-byte block. */
|
||||
{
|
||||
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
|
||||
Use the values for range checking, because if range checking is off,
|
||||
the extra bytes won't be missed terribly, but if range checking is on
|
||||
and we used a larger request, a whole extra 4096 bytes would be
|
||||
allocated.
|
||||
|
||||
These number are irrelevant to the new GNU malloc. I suspect it is
|
||||
less sensitive to the size of the request. */
|
||||
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
|
||||
+ 4 + DEFAULT_ROUNDING - 1)
|
||||
& ~(DEFAULT_ROUNDING - 1));
|
||||
size = 4096 - extra;
|
||||
}
|
||||
|
||||
h->chunk_size = size;
|
||||
h->alignment_mask = alignment - 1;
|
||||
|
||||
chunk = (struct _obstack_chunk *) call_chunkfun (h, h->chunk_size);
|
||||
if (!chunk)
|
||||
(*obstack_alloc_failed_handler) ();
|
||||
h->chunk = chunk;
|
||||
h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
|
||||
alignment - 1);
|
||||
h->chunk_limit = chunk->limit = (char *) chunk + h->chunk_size;
|
||||
chunk->prev = 0;
|
||||
/* The initial chunk now contains no empty object. */
|
||||
h->maybe_empty_object = 0;
|
||||
h->alloc_failed = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
_obstack_begin (struct obstack *h,
|
||||
_OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
|
||||
void *(*chunkfun) (size_t),
|
||||
void (*freefun) (void *))
|
||||
{
|
||||
h->chunkfun.plain = chunkfun;
|
||||
h->freefun.plain = freefun;
|
||||
h->use_extra_arg = 0;
|
||||
return _obstack_begin_worker (h, size, alignment);
|
||||
}
|
||||
|
||||
int
|
||||
_obstack_begin_1 (struct obstack *h,
|
||||
_OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
|
||||
void *(*chunkfun) (void *, size_t),
|
||||
void (*freefun) (void *, void *),
|
||||
void *arg)
|
||||
{
|
||||
h->chunkfun.extra = chunkfun;
|
||||
h->freefun.extra = freefun;
|
||||
h->extra_arg = arg;
|
||||
h->use_extra_arg = 1;
|
||||
return _obstack_begin_worker (h, size, alignment);
|
||||
}
|
||||
|
||||
/* Allocate a new current chunk for the obstack *H
|
||||
on the assumption that LENGTH bytes need to be added
|
||||
to the current object, or a new object of length LENGTH allocated.
|
||||
Copies any partial object from the end of the old chunk
|
||||
to the beginning of the new one. */
|
||||
|
||||
void
|
||||
_obstack_newchunk (struct obstack *h, _OBSTACK_SIZE_T length)
|
||||
{
|
||||
struct _obstack_chunk *old_chunk = h->chunk;
|
||||
struct _obstack_chunk *new_chunk = 0;
|
||||
size_t obj_size = h->next_free - h->object_base;
|
||||
char *object_base;
|
||||
|
||||
/* Compute size for new chunk. */
|
||||
size_t sum1 = obj_size + length;
|
||||
size_t sum2 = sum1 + h->alignment_mask;
|
||||
size_t new_size = sum2 + (obj_size >> 3) + 100;
|
||||
if (new_size < sum2)
|
||||
new_size = sum2;
|
||||
if (new_size < h->chunk_size)
|
||||
new_size = h->chunk_size;
|
||||
|
||||
/* Allocate and initialize the new chunk. */
|
||||
if (obj_size <= sum1 && sum1 <= sum2)
|
||||
new_chunk = (struct _obstack_chunk *) call_chunkfun (h, new_size);
|
||||
if (!new_chunk)
|
||||
(*obstack_alloc_failed_handler)();
|
||||
h->chunk = new_chunk;
|
||||
new_chunk->prev = old_chunk;
|
||||
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
|
||||
|
||||
/* Compute an aligned object_base in the new chunk */
|
||||
object_base =
|
||||
__PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
|
||||
|
||||
/* Move the existing object to the new chunk. */
|
||||
memcpy (object_base, h->object_base, obj_size);
|
||||
|
||||
/* If the object just copied was the only data in OLD_CHUNK,
|
||||
free that chunk and remove it from the chain.
|
||||
But not if that chunk might contain an empty object. */
|
||||
if (!h->maybe_empty_object
|
||||
&& (h->object_base
|
||||
== __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
|
||||
h->alignment_mask)))
|
||||
{
|
||||
new_chunk->prev = old_chunk->prev;
|
||||
call_freefun (h, old_chunk);
|
||||
}
|
||||
|
||||
h->object_base = object_base;
|
||||
h->next_free = h->object_base + obj_size;
|
||||
/* The new chunk certainly contains no empty object yet. */
|
||||
h->maybe_empty_object = 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if object OBJ has been allocated from obstack H.
|
||||
This is here for debugging.
|
||||
If you use it in a program, you are probably losing. */
|
||||
|
||||
/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
|
||||
obstack.h because it is just for debugging. */
|
||||
int _obstack_allocated_p (struct obstack *h, void *obj) __attribute_pure__;
|
||||
|
||||
int
|
||||
_obstack_allocated_p (struct obstack *h, void *obj)
|
||||
{
|
||||
struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
|
||||
struct _obstack_chunk *plp; /* point to previous chunk if any */
|
||||
|
||||
lp = (h)->chunk;
|
||||
/* We use >= rather than > since the object cannot be exactly at
|
||||
the beginning of the chunk but might be an empty object exactly
|
||||
at the end of an adjacent chunk. */
|
||||
while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
|
||||
{
|
||||
plp = lp->prev;
|
||||
lp = plp;
|
||||
}
|
||||
return lp != 0;
|
||||
}
|
||||
|
||||
/* Free objects in obstack H, including OBJ and everything allocate
|
||||
more recently than OBJ. If OBJ is zero, free everything in H. */
|
||||
|
||||
void
|
||||
_obstack_free (struct obstack *h, void *obj)
|
||||
{
|
||||
struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
|
||||
struct _obstack_chunk *plp; /* point to previous chunk if any */
|
||||
|
||||
lp = h->chunk;
|
||||
/* We use >= because there cannot be an object at the beginning of a chunk.
|
||||
But there can be an empty object at that address
|
||||
at the end of another chunk. */
|
||||
while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
|
||||
{
|
||||
plp = lp->prev;
|
||||
call_freefun (h, lp);
|
||||
lp = plp;
|
||||
/* If we switch chunks, we can't tell whether the new current
|
||||
chunk contains an empty object, so assume that it may. */
|
||||
h->maybe_empty_object = 1;
|
||||
}
|
||||
if (lp)
|
||||
{
|
||||
h->object_base = h->next_free = (char *) (obj);
|
||||
h->chunk_limit = lp->limit;
|
||||
h->chunk = lp;
|
||||
}
|
||||
else if (obj != 0)
|
||||
/* obj is not in any of the chunks! */
|
||||
abort ();
|
||||
}
|
||||
|
||||
_OBSTACK_SIZE_T
|
||||
_obstack_memory_used (struct obstack *h)
|
||||
{
|
||||
struct _obstack_chunk *lp;
|
||||
_OBSTACK_SIZE_T nbytes = 0;
|
||||
|
||||
for (lp = h->chunk; lp != 0; lp = lp->prev)
|
||||
{
|
||||
nbytes += lp->limit - (char *) lp;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
# ifndef _OBSTACK_NO_ERROR_HANDLER
|
||||
/* Define the error handler. */
|
||||
# include <stdio.h>
|
||||
|
||||
/* Exit value used when 'print_and_abort' is used. */
|
||||
# ifdef _LIBC
|
||||
int obstack_exit_failure = EXIT_FAILURE;
|
||||
# else
|
||||
# ifndef EXIT_FAILURE
|
||||
# define EXIT_FAILURE 1
|
||||
# endif
|
||||
# define obstack_exit_failure EXIT_FAILURE
|
||||
# endif
|
||||
|
||||
# if defined _LIBC || (HAVE_LIBINTL_H && ENABLE_NLS)
|
||||
# include <libintl.h>
|
||||
# ifndef _
|
||||
# define _(msgid) gettext (msgid)
|
||||
# endif
|
||||
# else
|
||||
# ifndef _
|
||||
# define _(msgid) (msgid)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !(defined _Noreturn \
|
||||
|| (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112))
|
||||
# if ((defined __GNUC__ \
|
||||
&& (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))) \
|
||||
|| (defined __SUNPRO_C && __SUNPRO_C >= 0x5110))
|
||||
# define _Noreturn __attribute__ ((__noreturn__))
|
||||
# elif defined _MSC_VER && _MSC_VER >= 1200
|
||||
# define _Noreturn __declspec (noreturn)
|
||||
# else
|
||||
# define _Noreturn
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef _LIBC
|
||||
# include <libio/iolibio.h>
|
||||
# endif
|
||||
|
||||
static _Noreturn void
|
||||
print_and_abort (void)
|
||||
{
|
||||
/* Don't change any of these strings. Yes, it would be possible to add
|
||||
the newline to the string and use fputs or so. But this must not
|
||||
happen because the "memory exhausted" message appears in other places
|
||||
like this and the translation should be reused instead of creating
|
||||
a very similar string which requires a separate translation. */
|
||||
# ifdef _LIBC
|
||||
(void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
|
||||
# else
|
||||
fprintf (stderr, "%s\n", _("memory exhausted"));
|
||||
# endif
|
||||
exit (obstack_exit_failure);
|
||||
}
|
||||
|
||||
/* The functions allocating more room by calling 'obstack_chunk_alloc'
|
||||
jump to the handler pointed to by 'obstack_alloc_failed_handler'.
|
||||
This can be set to a user defined function which should either
|
||||
abort gracefully or use longjump - but shouldn't return. This
|
||||
variable by default points to the internal function
|
||||
'print_and_abort'. */
|
||||
void (*obstack_alloc_failed_handler) (void) = print_and_abort;
|
||||
# endif /* !_OBSTACK_NO_ERROR_HANDLER */
|
||||
#endif /* !_OBSTACK_ELIDE_CODE */
|
535
obstack/obstack.h
Normal file
535
obstack/obstack.h
Normal file
@ -0,0 +1,535 @@
|
||||
/* obstack.h - object stack macros
|
||||
Copyright (C) 1988-2018 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Summary:
|
||||
|
||||
All the apparent functions defined here are macros. The idea
|
||||
is that you would use these pre-tested macros to solve a
|
||||
very specific set of problems, and they would run fast.
|
||||
Caution: no side-effects in arguments please!! They may be
|
||||
evaluated MANY times!!
|
||||
|
||||
These macros operate a stack of objects. Each object starts life
|
||||
small, and may grow to maturity. (Consider building a word syllable
|
||||
by syllable.) An object can move while it is growing. Once it has
|
||||
been "finished" it never changes address again. So the "top of the
|
||||
stack" is typically an immature growing object, while the rest of the
|
||||
stack is of mature, fixed size and fixed address objects.
|
||||
|
||||
These routines grab large chunks of memory, using a function you
|
||||
supply, called 'obstack_chunk_alloc'. On occasion, they free chunks,
|
||||
by calling 'obstack_chunk_free'. You must define them and declare
|
||||
them before using any obstack macros.
|
||||
|
||||
Each independent stack is represented by a 'struct obstack'.
|
||||
Each of the obstack macros expects a pointer to such a structure
|
||||
as the first argument.
|
||||
|
||||
One motivation for this package is the problem of growing char strings
|
||||
in symbol tables. Unless you are "fascist pig with a read-only mind"
|
||||
--Gosper's immortal quote from HAKMEM item 154, out of context--you
|
||||
would not like to put any arbitrary upper limit on the length of your
|
||||
symbols.
|
||||
|
||||
In practice this often means you will build many short symbols and a
|
||||
few long symbols. At the time you are reading a symbol you don't know
|
||||
how long it is. One traditional method is to read a symbol into a
|
||||
buffer, realloc()ating the buffer every time you try to read a symbol
|
||||
that is longer than the buffer. This is beaut, but you still will
|
||||
want to copy the symbol from the buffer to a more permanent
|
||||
symbol-table entry say about half the time.
|
||||
|
||||
With obstacks, you can work differently. Use one obstack for all symbol
|
||||
names. As you read a symbol, grow the name in the obstack gradually.
|
||||
When the name is complete, finalize it. Then, if the symbol exists already,
|
||||
free the newly read name.
|
||||
|
||||
The way we do this is to take a large chunk, allocating memory from
|
||||
low addresses. When you want to build a symbol in the chunk you just
|
||||
add chars above the current "high water mark" in the chunk. When you
|
||||
have finished adding chars, because you got to the end of the symbol,
|
||||
you know how long the chars are, and you can create a new object.
|
||||
Mostly the chars will not burst over the highest address of the chunk,
|
||||
because you would typically expect a chunk to be (say) 100 times as
|
||||
long as an average object.
|
||||
|
||||
In case that isn't clear, when we have enough chars to make up
|
||||
the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
|
||||
so we just point to it where it lies. No moving of chars is
|
||||
needed and this is the second win: potentially long strings need
|
||||
never be explicitly shuffled. Once an object is formed, it does not
|
||||
change its address during its lifetime.
|
||||
|
||||
When the chars burst over a chunk boundary, we allocate a larger
|
||||
chunk, and then copy the partly formed object from the end of the old
|
||||
chunk to the beginning of the new larger chunk. We then carry on
|
||||
accreting characters to the end of the object as we normally would.
|
||||
|
||||
A special macro is provided to add a single char at a time to a
|
||||
growing object. This allows the use of register variables, which
|
||||
break the ordinary 'growth' macro.
|
||||
|
||||
Summary:
|
||||
We allocate large chunks.
|
||||
We carve out one object at a time from the current chunk.
|
||||
Once carved, an object never moves.
|
||||
We are free to append data of any size to the currently
|
||||
growing object.
|
||||
Exactly one object is growing in an obstack at any one time.
|
||||
You can run one obstack per control block.
|
||||
You may have as many control blocks as you dare.
|
||||
Because of the way we do it, you can "unwind" an obstack
|
||||
back to a previous state. (You may remove objects much
|
||||
as you would with a stack.)
|
||||
*/
|
||||
|
||||
|
||||
/* Don't do the contents of this file more than once. */
|
||||
|
||||
#ifndef _OBSTACK_H
|
||||
#define _OBSTACK_H 1
|
||||
|
||||
#ifndef _OBSTACK_INTERFACE_VERSION
|
||||
# define _OBSTACK_INTERFACE_VERSION 2
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* For size_t and ptrdiff_t. */
|
||||
#include <string.h> /* For __GNU_LIBRARY__, and memcpy. */
|
||||
|
||||
#if _OBSTACK_INTERFACE_VERSION == 1
|
||||
/* For binary compatibility with obstack version 1, which used "int"
|
||||
and "long" for these two types. */
|
||||
# define _OBSTACK_SIZE_T unsigned int
|
||||
# define _CHUNK_SIZE_T unsigned long
|
||||
# define _OBSTACK_CAST(type, expr) ((type) (expr))
|
||||
#else
|
||||
/* Version 2 with sane types, especially for 64-bit hosts. */
|
||||
# define _OBSTACK_SIZE_T size_t
|
||||
# define _CHUNK_SIZE_T size_t
|
||||
# define _OBSTACK_CAST(type, expr) (expr)
|
||||
#endif
|
||||
|
||||
/* If B is the base of an object addressed by P, return the result of
|
||||
aligning P to the next multiple of A + 1. B and P must be of type
|
||||
char *. A + 1 must be a power of 2. */
|
||||
|
||||
#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
|
||||
|
||||
/* Similar to __BPTR_ALIGN (B, P, A), except optimize the common case
|
||||
where pointers can be converted to integers, aligned as integers,
|
||||
and converted back again. If ptrdiff_t is narrower than a
|
||||
pointer (e.g., the AS/400), play it safe and compute the alignment
|
||||
relative to B. Otherwise, use the faster strategy of computing the
|
||||
alignment relative to 0. */
|
||||
|
||||
#define __PTR_ALIGN(B, P, A) \
|
||||
__BPTR_ALIGN (sizeof (ptrdiff_t) < sizeof (void *) ? (B) : (char *) 0, \
|
||||
P, A)
|
||||
|
||||
#ifndef __attribute_pure__
|
||||
# if defined __GNUC_MINOR__ && __GNUC__ * 1000 + __GNUC_MINOR__ >= 2096
|
||||
# define __attribute_pure__ __attribute__ ((__pure__))
|
||||
# else
|
||||
# define __attribute_pure__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _obstack_chunk /* Lives at front of each chunk. */
|
||||
{
|
||||
char *limit; /* 1 past end of this chunk */
|
||||
struct _obstack_chunk *prev; /* address of prior chunk or NULL */
|
||||
char contents[4]; /* objects begin here */
|
||||
};
|
||||
|
||||
struct obstack /* control current object in current chunk */
|
||||
{
|
||||
_CHUNK_SIZE_T chunk_size; /* preferred size to allocate chunks in */
|
||||
struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
|
||||
char *object_base; /* address of object we are building */
|
||||
char *next_free; /* where to add next char to current object */
|
||||
char *chunk_limit; /* address of char after current chunk */
|
||||
union
|
||||
{
|
||||
_OBSTACK_SIZE_T i;
|
||||
void *p;
|
||||
} temp; /* Temporary for some macros. */
|
||||
_OBSTACK_SIZE_T alignment_mask; /* Mask of alignment for each object. */
|
||||
|
||||
/* These prototypes vary based on 'use_extra_arg'. */
|
||||
union
|
||||
{
|
||||
void *(*plain) (size_t);
|
||||
void *(*extra) (void *, size_t);
|
||||
} chunkfun;
|
||||
union
|
||||
{
|
||||
void (*plain) (void *);
|
||||
void (*extra) (void *, void *);
|
||||
} freefun;
|
||||
|
||||
void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
|
||||
unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */
|
||||
unsigned maybe_empty_object : 1; /* There is a possibility that the current
|
||||
chunk contains a zero-length object. This
|
||||
prevents freeing the chunk if we allocate
|
||||
a bigger chunk to replace it. */
|
||||
unsigned alloc_failed : 1; /* No longer used, as we now call the failed
|
||||
handler on error, but retained for binary
|
||||
compatibility. */
|
||||
};
|
||||
|
||||
/* Declare the external functions we use; they are in obstack.c. */
|
||||
|
||||
extern void _obstack_newchunk (struct obstack *, _OBSTACK_SIZE_T);
|
||||
extern void _obstack_free (struct obstack *, void *);
|
||||
extern int _obstack_begin (struct obstack *,
|
||||
_OBSTACK_SIZE_T, _OBSTACK_SIZE_T,
|
||||
void *(*) (size_t), void (*) (void *));
|
||||
extern int _obstack_begin_1 (struct obstack *,
|
||||
_OBSTACK_SIZE_T, _OBSTACK_SIZE_T,
|
||||
void *(*) (void *, size_t),
|
||||
void (*) (void *, void *), void *);
|
||||
extern _OBSTACK_SIZE_T _obstack_memory_used (struct obstack *)
|
||||
__attribute_pure__;
|
||||
|
||||
|
||||
/* Error handler called when 'obstack_chunk_alloc' failed to allocate
|
||||
more memory. This can be set to a user defined function which
|
||||
should either abort gracefully or use longjump - but shouldn't
|
||||
return. The default action is to print a message and abort. */
|
||||
extern void (*obstack_alloc_failed_handler) (void);
|
||||
|
||||
/* Exit value used when 'print_and_abort' is used. */
|
||||
extern int obstack_exit_failure;
|
||||
|
||||
/* Pointer to beginning of object being allocated or to be allocated next.
|
||||
Note that this might not be the final address of the object
|
||||
because a new chunk might be needed to hold the final size. */
|
||||
|
||||
#define obstack_base(h) ((void *) (h)->object_base)
|
||||
|
||||
/* Size for allocating ordinary chunks. */
|
||||
|
||||
#define obstack_chunk_size(h) ((h)->chunk_size)
|
||||
|
||||
/* Pointer to next byte not yet allocated in current chunk. */
|
||||
|
||||
#define obstack_next_free(h) ((void *) (h)->next_free)
|
||||
|
||||
/* Mask specifying low bits that should be clear in address of an object. */
|
||||
|
||||
#define obstack_alignment_mask(h) ((h)->alignment_mask)
|
||||
|
||||
/* To prevent prototype warnings provide complete argument list. */
|
||||
#define obstack_init(h) \
|
||||
_obstack_begin ((h), 0, 0, \
|
||||
_OBSTACK_CAST (void *(*) (size_t), obstack_chunk_alloc), \
|
||||
_OBSTACK_CAST (void (*) (void *), obstack_chunk_free))
|
||||
|
||||
#define obstack_begin(h, size) \
|
||||
_obstack_begin ((h), (size), 0, \
|
||||
_OBSTACK_CAST (void *(*) (size_t), obstack_chunk_alloc), \
|
||||
_OBSTACK_CAST (void (*) (void *), obstack_chunk_free))
|
||||
|
||||
#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
|
||||
_obstack_begin ((h), (size), (alignment), \
|
||||
_OBSTACK_CAST (void *(*) (size_t), chunkfun), \
|
||||
_OBSTACK_CAST (void (*) (void *), freefun))
|
||||
|
||||
#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
|
||||
_obstack_begin_1 ((h), (size), (alignment), \
|
||||
_OBSTACK_CAST (void *(*) (void *, size_t), chunkfun), \
|
||||
_OBSTACK_CAST (void (*) (void *, void *), freefun), arg)
|
||||
|
||||
#define obstack_chunkfun(h, newchunkfun) \
|
||||
((void) ((h)->chunkfun.extra = (void *(*) (void *, size_t)) (newchunkfun)))
|
||||
|
||||
#define obstack_freefun(h, newfreefun) \
|
||||
((void) ((h)->freefun.extra = (void *(*) (void *, void *)) (newfreefun)))
|
||||
|
||||
#define obstack_1grow_fast(h, achar) ((void) (*((h)->next_free)++ = (achar)))
|
||||
|
||||
#define obstack_blank_fast(h, n) ((void) ((h)->next_free += (n)))
|
||||
|
||||
#define obstack_memory_used(h) _obstack_memory_used (h)
|
||||
|
||||
#if defined __GNUC__
|
||||
# if !defined __GNUC_MINOR__ || __GNUC__ * 1000 + __GNUC_MINOR__ < 2008
|
||||
# define __extension__
|
||||
# endif
|
||||
|
||||
/* For GNU C, if not -traditional,
|
||||
we can define these macros to compute all args only once
|
||||
without using a global variable.
|
||||
Also, we can avoid using the 'temp' slot, to make faster code. */
|
||||
|
||||
# define obstack_object_size(OBSTACK) \
|
||||
__extension__ \
|
||||
({ struct obstack const *__o = (OBSTACK); \
|
||||
(_OBSTACK_SIZE_T) (__o->next_free - __o->object_base); })
|
||||
|
||||
/* The local variable is named __o1 to avoid a shadowed variable
|
||||
warning when invoked from other obstack macros. */
|
||||
# define obstack_room(OBSTACK) \
|
||||
__extension__ \
|
||||
({ struct obstack const *__o1 = (OBSTACK); \
|
||||
(_OBSTACK_SIZE_T) (__o1->chunk_limit - __o1->next_free); })
|
||||
|
||||
# define obstack_make_room(OBSTACK, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
_OBSTACK_SIZE_T __len = (length); \
|
||||
if (obstack_room (__o) < __len) \
|
||||
_obstack_newchunk (__o, __len); \
|
||||
(void) 0; })
|
||||
|
||||
# define obstack_empty_p(OBSTACK) \
|
||||
__extension__ \
|
||||
({ struct obstack const *__o = (OBSTACK); \
|
||||
(__o->chunk->prev == 0 \
|
||||
&& __o->next_free == __PTR_ALIGN ((char *) __o->chunk, \
|
||||
__o->chunk->contents, \
|
||||
__o->alignment_mask)); })
|
||||
|
||||
# define obstack_grow(OBSTACK, where, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
_OBSTACK_SIZE_T __len = (length); \
|
||||
if (obstack_room (__o) < __len) \
|
||||
_obstack_newchunk (__o, __len); \
|
||||
memcpy (__o->next_free, where, __len); \
|
||||
__o->next_free += __len; \
|
||||
(void) 0; })
|
||||
|
||||
# define obstack_grow0(OBSTACK, where, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
_OBSTACK_SIZE_T __len = (length); \
|
||||
if (obstack_room (__o) < __len + 1) \
|
||||
_obstack_newchunk (__o, __len + 1); \
|
||||
memcpy (__o->next_free, where, __len); \
|
||||
__o->next_free += __len; \
|
||||
*(__o->next_free)++ = 0; \
|
||||
(void) 0; })
|
||||
|
||||
# define obstack_1grow(OBSTACK, datum) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
if (obstack_room (__o) < 1) \
|
||||
_obstack_newchunk (__o, 1); \
|
||||
obstack_1grow_fast (__o, datum); })
|
||||
|
||||
/* These assume that the obstack alignment is good enough for pointers
|
||||
or ints, and that the data added so far to the current object
|
||||
shares that much alignment. */
|
||||
|
||||
# define obstack_ptr_grow(OBSTACK, datum) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
if (obstack_room (__o) < sizeof (void *)) \
|
||||
_obstack_newchunk (__o, sizeof (void *)); \
|
||||
obstack_ptr_grow_fast (__o, datum); })
|
||||
|
||||
# define obstack_int_grow(OBSTACK, datum) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
if (obstack_room (__o) < sizeof (int)) \
|
||||
_obstack_newchunk (__o, sizeof (int)); \
|
||||
obstack_int_grow_fast (__o, datum); })
|
||||
|
||||
# define obstack_ptr_grow_fast(OBSTACK, aptr) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o1 = (OBSTACK); \
|
||||
void *__p1 = __o1->next_free; \
|
||||
*(const void **) __p1 = (aptr); \
|
||||
__o1->next_free += sizeof (const void *); \
|
||||
(void) 0; })
|
||||
|
||||
# define obstack_int_grow_fast(OBSTACK, aint) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o1 = (OBSTACK); \
|
||||
void *__p1 = __o1->next_free; \
|
||||
*(int *) __p1 = (aint); \
|
||||
__o1->next_free += sizeof (int); \
|
||||
(void) 0; })
|
||||
|
||||
# define obstack_blank(OBSTACK, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
_OBSTACK_SIZE_T __len = (length); \
|
||||
if (obstack_room (__o) < __len) \
|
||||
_obstack_newchunk (__o, __len); \
|
||||
obstack_blank_fast (__o, __len); })
|
||||
|
||||
# define obstack_alloc(OBSTACK, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__h = (OBSTACK); \
|
||||
obstack_blank (__h, (length)); \
|
||||
obstack_finish (__h); })
|
||||
|
||||
# define obstack_copy(OBSTACK, where, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__h = (OBSTACK); \
|
||||
obstack_grow (__h, (where), (length)); \
|
||||
obstack_finish (__h); })
|
||||
|
||||
# define obstack_copy0(OBSTACK, where, length) \
|
||||
__extension__ \
|
||||
({ struct obstack *__h = (OBSTACK); \
|
||||
obstack_grow0 (__h, (where), (length)); \
|
||||
obstack_finish (__h); })
|
||||
|
||||
/* The local variable is named __o1 to avoid a shadowed variable
|
||||
warning when invoked from other obstack macros, typically obstack_free. */
|
||||
# define obstack_finish(OBSTACK) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o1 = (OBSTACK); \
|
||||
void *__value = (void *) __o1->object_base; \
|
||||
if (__o1->next_free == __value) \
|
||||
__o1->maybe_empty_object = 1; \
|
||||
__o1->next_free \
|
||||
= __PTR_ALIGN (__o1->object_base, __o1->next_free, \
|
||||
__o1->alignment_mask); \
|
||||
if ((size_t) (__o1->next_free - (char *) __o1->chunk) \
|
||||
> (size_t) (__o1->chunk_limit - (char *) __o1->chunk)) \
|
||||
__o1->next_free = __o1->chunk_limit; \
|
||||
__o1->object_base = __o1->next_free; \
|
||||
__value; })
|
||||
|
||||
# define obstack_free(OBSTACK, OBJ) \
|
||||
__extension__ \
|
||||
({ struct obstack *__o = (OBSTACK); \
|
||||
void *__obj = (void *) (OBJ); \
|
||||
if (__obj > (void *) __o->chunk && __obj < (void *) __o->chunk_limit) \
|
||||
__o->next_free = __o->object_base = (char *) __obj; \
|
||||
else \
|
||||
_obstack_free (__o, __obj); })
|
||||
|
||||
#else /* not __GNUC__ */
|
||||
|
||||
# define obstack_object_size(h) \
|
||||
((_OBSTACK_SIZE_T) ((h)->next_free - (h)->object_base))
|
||||
|
||||
# define obstack_room(h) \
|
||||
((_OBSTACK_SIZE_T) ((h)->chunk_limit - (h)->next_free))
|
||||
|
||||
# define obstack_empty_p(h) \
|
||||
((h)->chunk->prev == 0 \
|
||||
&& (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk, \
|
||||
(h)->chunk->contents, \
|
||||
(h)->alignment_mask))
|
||||
|
||||
/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
|
||||
so that we can avoid having void expressions
|
||||
in the arms of the conditional expression.
|
||||
Casting the third operand to void was tried before,
|
||||
but some compilers won't accept it. */
|
||||
|
||||
# define obstack_make_room(h, length) \
|
||||
((h)->temp.i = (length), \
|
||||
((obstack_room (h) < (h)->temp.i) \
|
||||
? (_obstack_newchunk (h, (h)->temp.i), 0) : 0), \
|
||||
(void) 0)
|
||||
|
||||
# define obstack_grow(h, where, length) \
|
||||
((h)->temp.i = (length), \
|
||||
((obstack_room (h) < (h)->temp.i) \
|
||||
? (_obstack_newchunk ((h), (h)->temp.i), 0) : 0), \
|
||||
memcpy ((h)->next_free, where, (h)->temp.i), \
|
||||
(h)->next_free += (h)->temp.i, \
|
||||
(void) 0)
|
||||
|
||||
# define obstack_grow0(h, where, length) \
|
||||
((h)->temp.i = (length), \
|
||||
((obstack_room (h) < (h)->temp.i + 1) \
|
||||
? (_obstack_newchunk ((h), (h)->temp.i + 1), 0) : 0), \
|
||||
memcpy ((h)->next_free, where, (h)->temp.i), \
|
||||
(h)->next_free += (h)->temp.i, \
|
||||
*((h)->next_free)++ = 0, \
|
||||
(void) 0)
|
||||
|
||||
# define obstack_1grow(h, datum) \
|
||||
(((obstack_room (h) < 1) \
|
||||
? (_obstack_newchunk ((h), 1), 0) : 0), \
|
||||
obstack_1grow_fast (h, datum))
|
||||
|
||||
# define obstack_ptr_grow(h, datum) \
|
||||
(((obstack_room (h) < sizeof (char *)) \
|
||||
? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
|
||||
obstack_ptr_grow_fast (h, datum))
|
||||
|
||||
# define obstack_int_grow(h, datum) \
|
||||
(((obstack_room (h) < sizeof (int)) \
|
||||
? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
|
||||
obstack_int_grow_fast (h, datum))
|
||||
|
||||
# define obstack_ptr_grow_fast(h, aptr) \
|
||||
(((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr), \
|
||||
(void) 0)
|
||||
|
||||
# define obstack_int_grow_fast(h, aint) \
|
||||
(((int *) ((h)->next_free += sizeof (int)))[-1] = (aint), \
|
||||
(void) 0)
|
||||
|
||||
# define obstack_blank(h, length) \
|
||||
((h)->temp.i = (length), \
|
||||
((obstack_room (h) < (h)->temp.i) \
|
||||
? (_obstack_newchunk ((h), (h)->temp.i), 0) : 0), \
|
||||
obstack_blank_fast (h, (h)->temp.i))
|
||||
|
||||
# define obstack_alloc(h, length) \
|
||||
(obstack_blank ((h), (length)), obstack_finish ((h)))
|
||||
|
||||
# define obstack_copy(h, where, length) \
|
||||
(obstack_grow ((h), (where), (length)), obstack_finish ((h)))
|
||||
|
||||
# define obstack_copy0(h, where, length) \
|
||||
(obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
|
||||
|
||||
# define obstack_finish(h) \
|
||||
(((h)->next_free == (h)->object_base \
|
||||
? (((h)->maybe_empty_object = 1), 0) \
|
||||
: 0), \
|
||||
(h)->temp.p = (h)->object_base, \
|
||||
(h)->next_free \
|
||||
= __PTR_ALIGN ((h)->object_base, (h)->next_free, \
|
||||
(h)->alignment_mask), \
|
||||
(((size_t) ((h)->next_free - (char *) (h)->chunk) \
|
||||
> (size_t) ((h)->chunk_limit - (char *) (h)->chunk)) \
|
||||
? ((h)->next_free = (h)->chunk_limit) : 0), \
|
||||
(h)->object_base = (h)->next_free, \
|
||||
(h)->temp.p)
|
||||
|
||||
# define obstack_free(h, obj) \
|
||||
((h)->temp.p = (void *) (obj), \
|
||||
(((h)->temp.p > (void *) (h)->chunk \
|
||||
&& (h)->temp.p < (void *) (h)->chunk_limit) \
|
||||
? (void) ((h)->next_free = (h)->object_base = (char *) (h)->temp.p) \
|
||||
: _obstack_free ((h), (h)->temp.p)))
|
||||
|
||||
#endif /* not __GNUC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* C++ */
|
||||
#endif
|
||||
|
||||
#endif /* _OBSTACK_H */
|
11
pam/crond
Normal file
11
pam/crond
Normal file
@ -0,0 +1,11 @@
|
||||
#
|
||||
# The PAM configuration file for the cron daemon
|
||||
#
|
||||
#
|
||||
# Although no PAM authentication is called, auth modules
|
||||
# are used for credential setting
|
||||
auth include system-auth
|
||||
account required pam_access.so
|
||||
account include system-auth
|
||||
session required pam_loginuid.so
|
||||
session include system-auth
|
118
src/Makemodule.am
Normal file
118
src/Makemodule.am
Normal file
@ -0,0 +1,118 @@
|
||||
# Makefile.am - two binaries crond and crontab
|
||||
|
||||
sbin_PROGRAMS += \
|
||||
src/crond
|
||||
|
||||
bin_PROGRAMS += \
|
||||
src/cronnext \
|
||||
src/crontab
|
||||
|
||||
src_crond_SOURCES = \
|
||||
src/cron.c \
|
||||
src/database.c \
|
||||
src/do_command.c \
|
||||
src/job.c \
|
||||
src/popen.c \
|
||||
src/security.c \
|
||||
src/user.c \
|
||||
cronie_common.c \
|
||||
$(common_src)
|
||||
|
||||
src_crontab_SOURCES = \
|
||||
src/crontab.c \
|
||||
src/security.c \
|
||||
$(common_src)
|
||||
|
||||
src_cronnext_SOURCES = \
|
||||
src/cronnext.c \
|
||||
src/database.c \
|
||||
src/job.c \
|
||||
src/user.c \
|
||||
$(common_src)
|
||||
|
||||
common_src = \
|
||||
src/bitstring.h \
|
||||
src/entry.c \
|
||||
src/env.c \
|
||||
src/externs.h \
|
||||
src/funcs.h \
|
||||
src/globals.h \
|
||||
src/macros.h \
|
||||
src/misc.c \
|
||||
src/pathnames.h \
|
||||
src/pw_dup.c \
|
||||
src/structs.h
|
||||
|
||||
common_nodist += cron-paths.h
|
||||
nodist_src_crond_SOURCES = $(common_nodist)
|
||||
nodist_src_crontab_SOURCES = $(common_nodist)
|
||||
nodist_src_cronnext_SOURCES = $(common_nodist)
|
||||
BUILT_SOURCES += $(common_nodist)
|
||||
|
||||
src_crond_LDADD = $(LIBSELINUX) $(LIBPAM) $(LIBAUDIT)
|
||||
src_crontab_LDADD = $(LIBSELINUX) $(LIBPAM) $(LIBAUDIT)
|
||||
|
||||
## if DEBUG
|
||||
## noinst_PROGRAMS = debug
|
||||
## endif
|
||||
|
||||
# This header contains all the paths.
|
||||
# If they are configurable, they are declared in configure script.
|
||||
# Depends on this Makefile, because it uses make variables.
|
||||
# CCD 2010/09/10 added CRON_HOSTNAME for clustered-cron.
|
||||
CLEANFILES += cron-paths.h
|
||||
if HAS_RUNSTATE
|
||||
cronpidcomment=/* directory of cron pid file */
|
||||
cronpiddir=\#define CRON_PID_DIR "$(runstatedir)"
|
||||
else
|
||||
cronpidcomment=
|
||||
cronpiddir=
|
||||
endif
|
||||
cron-paths.h: Makefile
|
||||
@echo 'creating $@'
|
||||
@sed >$@ 's/ *\\$$//' <<\END #\
|
||||
/* This file has been automatically generated. Do not edit. */ \
|
||||
\
|
||||
#ifndef _CRON_PATHS_H_ \
|
||||
#define _CRON_PATHS_H_ \
|
||||
\
|
||||
/* SPOOLDIR is where the crontabs live. \
|
||||
* This directory will have its modtime updated \
|
||||
* whenever crontab(1) changes a crontab; this is \
|
||||
* the signal for cron(8) to look at each individual \
|
||||
* crontab file and reload those whose modtimes are \
|
||||
* newer than they were last time around (or which \
|
||||
* didn't exist last time around...) \
|
||||
* or it will be checked by inotify \
|
||||
*/ \
|
||||
#define SPOOL_DIR "$(SPOOL_DIR)" \
|
||||
\
|
||||
/* CRON_HOSTNAME is file in SPOOL_DIR which, if it \
|
||||
* exists, and does not just contain a line matching \
|
||||
* the name returned by gethostname(), causes all \
|
||||
* crontabs in SPOOL_DIR to be ignored. This is \
|
||||
* intended to be used when clustering hosts sharing \
|
||||
* one NFS-mounted SPOOL_DIR, and where only one host \
|
||||
* should use the crontab files here at any one time. \
|
||||
*/ \
|
||||
#define CRON_HOSTNAME ".cron.hostname" \
|
||||
\
|
||||
/* cron allow/deny file. At least cron.deny must \
|
||||
* exist for ordinary users to run crontab. \
|
||||
*/ \
|
||||
#define CRON_ALLOW "$(sysconfdir)/cron.allow" \
|
||||
#define CRON_DENY "$(sysconfdir)/cron.deny" \
|
||||
\
|
||||
$(cronpidcomment) \
|
||||
$(cronpiddir) \
|
||||
\
|
||||
/* 4.3BSD-style crontab f.e. /etc/crontab */ \
|
||||
#define SYSCRONTAB "$(SYSCRONTAB)" \
|
||||
\
|
||||
/* system crontab dir f.e. /etc/cron.d/ */ \
|
||||
#define SYS_CROND_DIR "$(SYS_CROND_DIR)" \
|
||||
\
|
||||
#define SYSCONFDIR "$(sysconfdir)" \
|
||||
\
|
||||
#endif /* _CRON_PATHS_H_ */ \
|
||||
END
|
141
src/bitstring.h
Normal file
141
src/bitstring.h
Normal file
@ -0,0 +1,141 @@
|
||||
/* $NetBSD: bitstring.h,v 1.3 2003/08/07 11:17:08 agc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Paul Vixie.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)bitstring.h 8.1 (Berkeley) 7/19/93
|
||||
*/
|
||||
|
||||
#ifndef _BITSTRING_H_
|
||||
#define _BITSTRING_H_
|
||||
|
||||
typedef unsigned char bitstr_t;
|
||||
|
||||
/* internal macros */
|
||||
/* byte of the bitstring bit is in */
|
||||
#define _bit_byte(bit) \
|
||||
((bit) >> 3)
|
||||
|
||||
/* mask for the bit within its byte */
|
||||
#define _bit_mask(bit) \
|
||||
(1 << ((bit)&0x7))
|
||||
|
||||
/* external macros */
|
||||
/* bytes in a bitstring of nbits bits */
|
||||
#define bitstr_size(nbits) \
|
||||
((((nbits) - 1) >> 3) + 1)
|
||||
|
||||
/* allocate a bitstring */
|
||||
#define bit_alloc(nbits) \
|
||||
(bitstr_t *)calloc(1, \
|
||||
(unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
|
||||
|
||||
/* allocate a bitstring on the stack */
|
||||
#define bit_decl(name, nbits) \
|
||||
(name)[bitstr_size(nbits)]
|
||||
|
||||
/* is bit N of bitstring name set? */
|
||||
#define bit_test(name, bit) \
|
||||
((name)[_bit_byte(bit)] & _bit_mask(bit))
|
||||
|
||||
/* set bit N of bitstring name */
|
||||
#define bit_set(name, bit) \
|
||||
(name)[_bit_byte(bit)] |= (bitstr_t)_bit_mask(bit)
|
||||
|
||||
/* clear bit N of bitstring name */
|
||||
#define bit_clear(name, bit) \
|
||||
(name)[_bit_byte(bit)] &= (bitstr_t)~_bit_mask(bit)
|
||||
|
||||
/* clear bits start ... stop in bitstring */
|
||||
#define bit_nclear(name, start, stop) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _start = start, _stop = stop; \
|
||||
register int _startbyte = _bit_byte(_start); \
|
||||
register int _stopbyte = _bit_byte(_stop); \
|
||||
if (_startbyte == _stopbyte) { \
|
||||
_name[_startbyte] &= (bitstr_t)((0xff >> (8 - (_start&0x7))) | \
|
||||
(0xff << ((_stop&0x7) + 1))); \
|
||||
} else { \
|
||||
_name[_startbyte] &= (bitstr_t)(0xff >> (8 - (_start&0x7))); \
|
||||
while (++_startbyte < _stopbyte) \
|
||||
_name[_startbyte] = 0; \
|
||||
_name[_stopbyte] &= (bitstr_t)(0xff << ((_stop&0x7) + 1)); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* set bits start ... stop in bitstring */
|
||||
#define bit_nset(name, start, stop) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _start = start, _stop = stop; \
|
||||
register int _startbyte = _bit_byte(_start); \
|
||||
register int _stopbyte = _bit_byte(_stop); \
|
||||
if (_startbyte == _stopbyte) { \
|
||||
_name[_startbyte] |= (bitstr_t)((0xff << (_start&0x7)) & \
|
||||
(0xff >> (7 - (_stop&0x7)))); \
|
||||
} else { \
|
||||
_name[_startbyte] |= (bitstr_t)(0xff << ((_start)&0x7)); \
|
||||
while (++_startbyte < _stopbyte) \
|
||||
_name[_startbyte] = 0xff; \
|
||||
_name[_stopbyte] |= (bitstr_t)(0xff >> (7 - (_stop&0x7))); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* find first bit clear in name */
|
||||
#define bit_ffc(name, nbits, value) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _byte, _nbits = nbits; \
|
||||
register int _stopbyte = _bit_byte(_nbits), _value = -1; \
|
||||
for (_byte = 0; _byte <= _stopbyte; ++_byte) \
|
||||
if (_name[_byte] != 0xff) { \
|
||||
_value = _byte << 3; \
|
||||
for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
|
||||
++_value, _stopbyte >>= 1); \
|
||||
break; \
|
||||
} \
|
||||
*(value) = _value; \
|
||||
}
|
||||
|
||||
/* find first bit set in name */
|
||||
#define bit_ffs(name, nbits, value) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _byte, _nbits = nbits; \
|
||||
register int _stopbyte = _bit_byte(_nbits), _value = -1; \
|
||||
for (_byte = 0; _byte <= _stopbyte; ++_byte) \
|
||||
if (_name[_byte]) { \
|
||||
_value = _byte << 3; \
|
||||
for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
|
||||
++_value, _stopbyte >>= 1); \
|
||||
break; \
|
||||
} \
|
||||
*(value) = _value; \
|
||||
}
|
||||
|
||||
#endif /* !_BITSTRING_H_ */
|
731
src/cron.c
Normal file
731
src/cron.c
Normal file
@ -0,0 +1,731 @@
|
||||
/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified 2010/09/12 by Colin Dean, Durham University IT Service,
|
||||
* to add clustering support.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define MAIN_PROGRAM
|
||||
|
||||
#include <errno.h>
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef WITH_INOTIFY
|
||||
# include <sys/inotify.h>
|
||||
#endif
|
||||
|
||||
#include "cronie_common.h"
|
||||
#include "funcs.h"
|
||||
#include "globals.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#if defined WITH_INOTIFY
|
||||
int inotify_enabled;
|
||||
#else
|
||||
# define inotify_enabled 0
|
||||
#endif
|
||||
|
||||
enum timejump { negative, small, medium, large };
|
||||
|
||||
static void usage(void) ATTRIBUTE_NORETURN,
|
||||
run_reboot_jobs(cron_db *),
|
||||
find_jobs(int, cron_db *, int, int, long),
|
||||
set_time(int),
|
||||
cron_sleep(int, cron_db *),
|
||||
sigchld_handler(int),
|
||||
sighup_handler(int ATTRIBUTE_UNUSED),
|
||||
sigchld_reaper(void),
|
||||
sigintterm_handler(int ATTRIBUTE_UNUSED), parse_args(int c, char *v[]);
|
||||
|
||||
static volatile sig_atomic_t got_sighup, got_sigchld, got_sigintterm;
|
||||
static int timeRunning, virtualTime, clockTime;
|
||||
static long GMToff;
|
||||
static int DisableInotify;
|
||||
|
||||
#if defined WITH_INOTIFY
|
||||
|
||||
/*
|
||||
* Note that inotify isn't safe to use with clustering, as changes made
|
||||
* to a shared filesystem on one system cannot be relied on to be notified
|
||||
* on another system, so use of inotify is disabled at runtime if run with
|
||||
* clustering enabled.
|
||||
*/
|
||||
|
||||
# if defined ENABLE_SYSCRONTAB
|
||||
# define NUM_WATCHES 3
|
||||
|
||||
int wd[NUM_WATCHES];
|
||||
const char *watchpaths[NUM_WATCHES] = {SPOOL_DIR, SYS_CROND_DIR, SYSCRONTAB};
|
||||
# else
|
||||
# define NUM_WATCHES 2
|
||||
int wd[NUM_WATCHES];
|
||||
const char *watchpaths[NUM_WATCHES] = {SPOOL_DIR, SYS_CROND_DIR};
|
||||
# endif
|
||||
|
||||
static void reset_watches(void) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
|
||||
wd[i] = -2;
|
||||
}
|
||||
}
|
||||
|
||||
void set_cron_unwatched(int fd) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
|
||||
if (wd[i] > 0) {
|
||||
inotify_rm_watch(fd, wd[i]);
|
||||
wd[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_cron_watched(int fd) {
|
||||
pid_t pid = getpid();
|
||||
size_t i;
|
||||
|
||||
if (fd < 0) {
|
||||
inotify_enabled = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
|
||||
int w;
|
||||
|
||||
w = inotify_add_watch(fd, watchpaths[i],
|
||||
IN_CREATE | IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO |
|
||||
IN_MOVED_FROM | IN_MOVE_SELF | IN_DELETE | IN_DELETE_SELF);
|
||||
if (w < 0 && errno != ENOENT) {
|
||||
if (wd[i] != -1) {
|
||||
log_it("CRON", pid, "This directory or file can't be watched",
|
||||
watchpaths[i], errno);
|
||||
log_it("CRON", pid, "INFO", "running without inotify support",
|
||||
0);
|
||||
}
|
||||
inotify_enabled = 0;
|
||||
set_cron_unwatched(fd);
|
||||
return;
|
||||
}
|
||||
wd[i] = w;
|
||||
}
|
||||
|
||||
if (!inotify_enabled) {
|
||||
log_it("CRON", pid, "INFO", "running with inotify support", 0);
|
||||
}
|
||||
|
||||
inotify_enabled = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void handle_signals(cron_db * database) {
|
||||
if (got_sighup) {
|
||||
got_sighup = 0;
|
||||
#if defined WITH_INOTIFY
|
||||
/* watches must be reinstated on reload */
|
||||
if (inotify_enabled && (EnableClustering != 1)) {
|
||||
set_cron_unwatched(database->ifd);
|
||||
reset_watches();
|
||||
inotify_enabled = 0;
|
||||
}
|
||||
#endif
|
||||
database->mtime = (time_t) 0;
|
||||
log_close();
|
||||
}
|
||||
|
||||
if (got_sigchld) {
|
||||
got_sigchld = 0;
|
||||
sigchld_reaper();
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
const char **dflags;
|
||||
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, " %s [options]\n", ProgramName);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -h print this message \n");
|
||||
fprintf(stderr, " -i deamon runs without inotify support\n");
|
||||
fprintf(stderr, " -m <comm> off, or specify preferred client for sending mails\n");
|
||||
fprintf(stderr, " -n run in foreground\n");
|
||||
fprintf(stderr, " -f run in foreground, the same as -n\n");
|
||||
fprintf(stderr, " -p permit any crontab\n");
|
||||
fprintf(stderr, " -P inherit PATH from environment instead of using default value");
|
||||
fprintf(stderr, " of \"%s\"\n", _PATH_DEFPATH);
|
||||
fprintf(stderr, " -c enable clustering support\n");
|
||||
fprintf(stderr, " -s log into syslog instead of sending mails\n");
|
||||
fprintf(stderr, " -V print version and exit\n");
|
||||
fprintf(stderr, " -x <flag> print debug information\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Debugging flags are: ");
|
||||
for (dflags = DebugFlagNames; *dflags; dflags++)
|
||||
fprintf(stderr, "%s%s", *dflags, dflags[1] ? "," : "\n");
|
||||
exit(ERROR_EXIT);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sigaction sact;
|
||||
cron_db database;
|
||||
int fd;
|
||||
char *cs;
|
||||
pid_t pid = getpid();
|
||||
long oldGMToff;
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
char buf[256];
|
||||
|
||||
if ((ProgramName=strrchr(argv[0], '/')) == NULL) {
|
||||
ProgramName = argv[0];
|
||||
}
|
||||
else {
|
||||
++ProgramName;
|
||||
}
|
||||
|
||||
MailCmd[0] = '\0';
|
||||
cron_default_mail_charset[0] = '\0';
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
#if defined(BSD)
|
||||
setlinebuf(stdout);
|
||||
setlinebuf(stderr);
|
||||
#endif
|
||||
|
||||
SyslogOutput = 0;
|
||||
NoFork = 0;
|
||||
ChangePath = 1;
|
||||
parse_args(argc, argv);
|
||||
|
||||
memset((char *) &sact, 0, sizeof sact);
|
||||
sigemptyset(&sact.sa_mask);
|
||||
sact.sa_flags = 0;
|
||||
#ifdef SA_RESTART
|
||||
sact.sa_flags |= SA_RESTART;
|
||||
#endif
|
||||
sact.sa_handler = sigchld_handler;
|
||||
(void) sigaction(SIGCHLD, &sact, NULL);
|
||||
sact.sa_handler = sighup_handler;
|
||||
(void) sigaction(SIGHUP, &sact, NULL);
|
||||
sact.sa_handler = sigintterm_handler;
|
||||
(void) sigaction(SIGINT, &sact, NULL);
|
||||
(void) sigaction(SIGTERM, &sact, NULL);
|
||||
|
||||
acquire_daemonlock(0);
|
||||
set_cron_uid();
|
||||
check_spool_dir();
|
||||
|
||||
if (ChangePath) {
|
||||
if (setenv("PATH", _PATH_DEFPATH, 1) < 0) {
|
||||
log_it("CRON", pid, "DEATH", "can't setenv PATH",
|
||||
errno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the default locale character set for the mail
|
||||
* "Content-Type: ...; charset=" header
|
||||
*/
|
||||
setlocale(LC_ALL, ""); /* set locale to system defaults or to
|
||||
* that specified by any LC_* env vars */
|
||||
if ((cs = nl_langinfo(CODESET)) != NULL)
|
||||
strncpy(cron_default_mail_charset, cs, MAX_ENVSTR-1);
|
||||
else
|
||||
strcpy(cron_default_mail_charset, "US-ASCII");
|
||||
|
||||
/* if there are no debug flags turned on, fork as a daemon should.
|
||||
*/
|
||||
if (DebugFlags) {
|
||||
#if DEBUGGING
|
||||
(void) fprintf(stderr, "[%ld] cron started\n", (long) getpid());
|
||||
#endif
|
||||
}
|
||||
else if (NoFork == 0) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
log_it("CRON", pid, "DEATH", "can't fork", errno);
|
||||
exit(0);
|
||||
break;
|
||||
case 0:
|
||||
/* child process */
|
||||
(void) setsid();
|
||||
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) >= 0) {
|
||||
(void) dup2(fd, STDIN);
|
||||
(void) dup2(fd, STDOUT);
|
||||
(void) dup2(fd, STDERR);
|
||||
if (fd != STDERR)
|
||||
(void) close(fd);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* parent process should just die */
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
log_it("CRON", getpid(), "STARTUP", PACKAGE_VERSION, 0);
|
||||
|
||||
if (!SyslogOutput && MailCmd[0] == '\0' && access("/usr/sbin/sendmail", X_OK) != 0) {
|
||||
SyslogOutput=1;
|
||||
log_it("CRON", pid, "INFO","Syslog will be used instead of sendmail.", 0);
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
|
||||
/* obtain a random scaling factor for RANDOM_DELAY */
|
||||
if (gettimeofday(&tv, &tz) != 0)
|
||||
tv.tv_usec = 0;
|
||||
srandom((unsigned int)(pid + tv.tv_usec));
|
||||
RandomScale = (double)random() / (double)(1lu << 31);
|
||||
snprintf(buf, sizeof(buf), "RANDOM_DELAY will be scaled with factor %d%% if used.", (int)(RandomScale*100));
|
||||
log_it("CRON", pid, "INFO", buf, 0);
|
||||
|
||||
acquire_daemonlock(0);
|
||||
|
||||
fd = -1;
|
||||
#if defined WITH_INOTIFY
|
||||
if (DisableInotify || EnableClustering) {
|
||||
log_it("CRON", getpid(), "No inotify - daemon runs with -i or -c option",
|
||||
"", 0);
|
||||
}
|
||||
else {
|
||||
reset_watches();
|
||||
database.ifd = fd = inotify_init();
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
log_it("CRON", pid, "INFO", "Inotify init failed", errno);
|
||||
set_cron_watched(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
database.head = NULL;
|
||||
database.tail = NULL;
|
||||
database.mtime = (time_t) 0;
|
||||
|
||||
load_database(&database);
|
||||
|
||||
set_time(TRUE);
|
||||
run_reboot_jobs(&database);
|
||||
timeRunning = virtualTime = clockTime;
|
||||
oldGMToff = GMToff;
|
||||
|
||||
/*
|
||||
* Too many clocks, not enough time (Al. Einstein)
|
||||
* These clocks are in minutes since the epoch, adjusted for timezone.
|
||||
* virtualTime: is the time it *would* be if we woke up
|
||||
* promptly and nobody ever changed the clock. It is
|
||||
* monotonically increasing... unless a timejump happens.
|
||||
* At the top of the loop, all jobs for 'virtualTime' have run.
|
||||
* timeRunning: is the time we last awakened.
|
||||
* clockTime: is the time when set_time was last called.
|
||||
*/
|
||||
while (!got_sigintterm) {
|
||||
int timeDiff;
|
||||
enum timejump wakeupKind;
|
||||
|
||||
/* ... wait for the time (in minutes) to change ... */
|
||||
do {
|
||||
cron_sleep(timeRunning + 1, &database);
|
||||
set_time(FALSE);
|
||||
} while (!got_sigintterm && clockTime == timeRunning);
|
||||
if (got_sigintterm)
|
||||
break;
|
||||
timeRunning = clockTime;
|
||||
|
||||
/*
|
||||
* Calculate how the current time differs from our virtual
|
||||
* clock. Classify the change into one of 4 cases.
|
||||
*/
|
||||
timeDiff = timeRunning - virtualTime;
|
||||
check_orphans(&database);
|
||||
#if defined WITH_INOTIFY
|
||||
if (inotify_enabled) {
|
||||
check_inotify_database(&database);
|
||||
}
|
||||
else {
|
||||
if (load_database(&database) && (EnableClustering != 1))
|
||||
/* try reinstating the watches */
|
||||
set_cron_watched(fd);
|
||||
}
|
||||
#else
|
||||
load_database(&database);
|
||||
#endif
|
||||
|
||||
/* shortcut for the most common case */
|
||||
if (timeDiff == 1) {
|
||||
virtualTime = timeRunning;
|
||||
oldGMToff = GMToff;
|
||||
find_jobs(virtualTime, &database, TRUE, TRUE, oldGMToff);
|
||||
}
|
||||
else {
|
||||
if (timeDiff > (3 * MINUTE_COUNT) || timeDiff < -(3 * MINUTE_COUNT))
|
||||
wakeupKind = large;
|
||||
else if (timeDiff > 5)
|
||||
wakeupKind = medium;
|
||||
else if (timeDiff > 0)
|
||||
wakeupKind = small;
|
||||
else
|
||||
wakeupKind = negative;
|
||||
|
||||
switch (wakeupKind) {
|
||||
case small:
|
||||
/*
|
||||
* case 1: timeDiff is a small positive number
|
||||
* (wokeup late) run jobs for each virtual
|
||||
* minute until caught up.
|
||||
*/
|
||||
Debug(DSCH, ("[%ld], normal case %d minutes to go\n",
|
||||
(long) pid, timeDiff));
|
||||
do {
|
||||
if (job_runqueue())
|
||||
sleep(10);
|
||||
virtualTime++;
|
||||
if (virtualTime >= timeRunning)
|
||||
/* always run also the other timezone jobs in the last step */
|
||||
oldGMToff = GMToff;
|
||||
find_jobs(virtualTime, &database, TRUE, TRUE, oldGMToff);
|
||||
} while (virtualTime < timeRunning);
|
||||
break;
|
||||
|
||||
case medium:
|
||||
/*
|
||||
* case 2: timeDiff is a medium-sized positive
|
||||
* number, for example because we went to DST
|
||||
* run wildcard jobs once, then run any
|
||||
* fixed-time jobs that would otherwise be
|
||||
* skipped if we use up our minute (possible,
|
||||
* if there are a lot of jobs to run) go
|
||||
* around the loop again so that wildcard jobs
|
||||
* have a chance to run, and we do our
|
||||
* housekeeping.
|
||||
*/
|
||||
Debug(DSCH, ("[%ld], DST begins %d minutes to go\n",
|
||||
(long) pid, timeDiff));
|
||||
/* run wildcard jobs for current minute */
|
||||
find_jobs(timeRunning, &database, TRUE, FALSE, GMToff);
|
||||
|
||||
/* run fixed-time jobs for each minute missed */
|
||||
do {
|
||||
if (job_runqueue())
|
||||
sleep(10);
|
||||
virtualTime++;
|
||||
if (virtualTime >= timeRunning)
|
||||
/* always run also the other timezone jobs in the last step */
|
||||
oldGMToff = GMToff;
|
||||
find_jobs(virtualTime, &database, FALSE, TRUE, oldGMToff);
|
||||
set_time(FALSE);
|
||||
} while (virtualTime < timeRunning && clockTime == timeRunning);
|
||||
break;
|
||||
|
||||
case negative:
|
||||
/*
|
||||
* case 3: timeDiff is a small or medium-sized
|
||||
* negative num, eg. because of DST ending.
|
||||
* Just run the wildcard jobs. The fixed-time
|
||||
* jobs probably have already run, and should
|
||||
* not be repeated. Virtual time does not
|
||||
* change until we are caught up.
|
||||
*/
|
||||
Debug(DSCH, ("[%ld], DST ends %d minutes to go\n",
|
||||
(long) pid, timeDiff));
|
||||
find_jobs(timeRunning, &database, TRUE, FALSE, GMToff);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* other: time has changed a *lot*,
|
||||
* jump virtual time, and run everything
|
||||
*/
|
||||
Debug(DSCH, ("[%ld], clock jumped\n", (long) pid));
|
||||
virtualTime = timeRunning;
|
||||
oldGMToff = GMToff;
|
||||
find_jobs(timeRunning, &database, TRUE, TRUE, GMToff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Jobs to be run (if any) are loaded; clear the queue. */
|
||||
job_runqueue();
|
||||
|
||||
handle_signals(&database);
|
||||
}
|
||||
|
||||
#if defined WITH_INOTIFY
|
||||
if (inotify_enabled && (EnableClustering != 1))
|
||||
set_cron_unwatched(fd);
|
||||
|
||||
if (fd >= 0 && close(fd) < 0)
|
||||
log_it("CRON", pid, "INFO", "Inotify close failed", errno);
|
||||
#endif
|
||||
|
||||
log_it("CRON", pid, "INFO", "Shutting down", 0);
|
||||
|
||||
(void) unlink(_PATH_CRON_PID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_reboot_jobs(cron_db * db) {
|
||||
user *u;
|
||||
entry *e;
|
||||
int reboot;
|
||||
pid_t pid = getpid();
|
||||
|
||||
/* lock exist - skip reboot jobs */
|
||||
if (access(REBOOT_LOCK, F_OK) == 0) {
|
||||
log_it("CRON", pid, "INFO",
|
||||
"@reboot jobs will be run at computer's startup.", 0);
|
||||
return;
|
||||
}
|
||||
/* lock doesn't exist - create lock, run reboot jobs */
|
||||
if ((reboot = creat(REBOOT_LOCK, S_IRUSR & S_IWUSR)) < 0)
|
||||
log_it("CRON", pid, "INFO", "Can't create lock for reboot jobs.",
|
||||
errno);
|
||||
else
|
||||
close(reboot);
|
||||
|
||||
for (u = db->head; u != NULL; u = u->next) {
|
||||
for (e = u->crontab; e != NULL; e = e->next) {
|
||||
if (e->flags & WHEN_REBOOT)
|
||||
job_add(e, u);
|
||||
}
|
||||
}
|
||||
(void) job_runqueue();
|
||||
}
|
||||
|
||||
static void find_jobs(int vtime, cron_db * db, int doWild, int doNonWild, long vGMToff) {
|
||||
char *orig_tz, *job_tz;
|
||||
struct tm *tm;
|
||||
int minute, hour, dom, month, dow;
|
||||
user *u;
|
||||
entry *e;
|
||||
|
||||
/* The support for the job-specific timezones is not perfect. There will
|
||||
* be jobs missed or run twice during the DST change in the job timezone.
|
||||
* It is recommended not to schedule any jobs during the hour when
|
||||
* the DST changes happen if job-specific timezones are used.
|
||||
*
|
||||
* Make 0-based values out of tm values so we can use them as indicies
|
||||
*/
|
||||
#define maketime(tz1, tz2) do { \
|
||||
char *t = tz1; \
|
||||
if (t != NULL && *t != '\0') { \
|
||||
setenv("TZ", t, 1); \
|
||||
tm = localtime(&virtualGMTSecond); \
|
||||
} else { if ((tz2) != NULL) \
|
||||
setenv("TZ", (tz2), 1); \
|
||||
else \
|
||||
unsetenv("TZ"); \
|
||||
tm = gmtime(&virtualSecond); \
|
||||
} \
|
||||
minute = tm->tm_min -FIRST_MINUTE; \
|
||||
hour = tm->tm_hour -FIRST_HOUR; \
|
||||
dom = tm->tm_mday -FIRST_DOM; \
|
||||
month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH; \
|
||||
dow = tm->tm_wday -FIRST_DOW; \
|
||||
} while (0)
|
||||
|
||||
orig_tz = getenv("TZ");
|
||||
|
||||
/* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
|
||||
* first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
|
||||
* on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
|
||||
* is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
|
||||
* like many bizarre things, it's the standard.
|
||||
*/
|
||||
for (u = db->head; u != NULL; u = u->next) {
|
||||
for (e = u->crontab; e != NULL; e = e->next) {
|
||||
time_t virtualSecond = (time_t)(vtime - e->delay) * (time_t)SECONDS_PER_MINUTE;
|
||||
time_t virtualGMTSecond = virtualSecond - vGMToff;
|
||||
job_tz = env_get("CRON_TZ", e->envp);
|
||||
maketime(job_tz, orig_tz);
|
||||
|
||||
/* here we test whether time is NOW */
|
||||
if (bit_test(e->minute, minute) &&
|
||||
bit_test(e->hour, hour) &&
|
||||
bit_test(e->month, month) &&
|
||||
(((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
|
||||
? (bit_test(e->dow, dow) && bit_test(e->dom, dom))
|
||||
: (bit_test(e->dow, dow) || bit_test(e->dom, dom))
|
||||
)
|
||||
) {
|
||||
if (job_tz != NULL && vGMToff != GMToff)
|
||||
/* do not try to run the jobs from different timezones
|
||||
* during the DST switch of the default timezone.
|
||||
*/
|
||||
continue;
|
||||
|
||||
if ((doNonWild &&
|
||||
!(e->flags & (MIN_STAR | HR_STAR))) ||
|
||||
(doWild && (e->flags & (MIN_STAR | HR_STAR))))
|
||||
job_add(e, u); /*will add job, if it isn't in queue already for NOW. */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (orig_tz != NULL)
|
||||
setenv("TZ", orig_tz, 1);
|
||||
else
|
||||
unsetenv("TZ");
|
||||
}
|
||||
|
||||
/*
|
||||
* Set StartTime and clockTime to the current time.
|
||||
* These are used for computing what time it really is right now.
|
||||
* Note that clockTime is a unix wallclock time converted to minutes.
|
||||
*/
|
||||
static void set_time(int initialize) {
|
||||
struct tm tm;
|
||||
static int isdst;
|
||||
|
||||
StartTime = time(NULL);
|
||||
|
||||
/* We adjust the time to GMT so we can catch DST changes. */
|
||||
tm = *localtime(&StartTime);
|
||||
if (initialize || tm.tm_isdst != isdst) {
|
||||
isdst = tm.tm_isdst;
|
||||
GMToff = get_gmtoff(&StartTime, &tm);
|
||||
Debug(DSCH, ("[%ld] GMToff=%ld\n", (long) getpid(), (long) GMToff));
|
||||
}
|
||||
clockTime = (int)((StartTime + GMToff) / (time_t) SECONDS_PER_MINUTE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to just hit the next minute.
|
||||
*/
|
||||
static void cron_sleep(int target, cron_db * db) {
|
||||
time_t t1, t2;
|
||||
int seconds_to_wait;
|
||||
|
||||
t1 = time(NULL) + GMToff;
|
||||
seconds_to_wait = (int) (target * SECONDS_PER_MINUTE - t1) + 1;
|
||||
Debug(DSCH, ("[%ld] Target time=%ld, sec-to-wait=%d\n",
|
||||
(long) getpid(), (long) target * SECONDS_PER_MINUTE,
|
||||
seconds_to_wait));
|
||||
|
||||
while (seconds_to_wait > 0 && seconds_to_wait < 65) {
|
||||
sleep((unsigned int) seconds_to_wait);
|
||||
|
||||
if (got_sigintterm)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Check to see if we were interrupted by a signal.
|
||||
* If so, service the signal(s) then continue sleeping
|
||||
* where we left off.
|
||||
*/
|
||||
handle_signals(db);
|
||||
|
||||
t2 = time(NULL) + GMToff;
|
||||
seconds_to_wait -= (int) (t2 - t1);
|
||||
t1 = t2;
|
||||
}
|
||||
}
|
||||
|
||||
static void sighup_handler(int x ATTRIBUTE_UNUSED) {
|
||||
got_sighup = 1;
|
||||
}
|
||||
|
||||
static void sigchld_handler(int x ATTRIBUTE_UNUSED) {
|
||||
got_sigchld = 1;
|
||||
}
|
||||
|
||||
static void sigintterm_handler(int x ATTRIBUTE_UNUSED) {
|
||||
got_sigintterm = 1;
|
||||
}
|
||||
|
||||
static void sigchld_reaper(void) {
|
||||
WAIT_T waiter;
|
||||
PID_T pid;
|
||||
|
||||
do {
|
||||
pid = waitpid(-1, &waiter, WNOHANG);
|
||||
switch (pid) {
|
||||
case -1:
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Debug(DPROC, ("[%ld] sigchld...no children\n", (long) getpid()));
|
||||
break;
|
||||
case 0:
|
||||
Debug(DPROC, ("[%ld] sigchld...no dead kids\n", (long) getpid()));
|
||||
break;
|
||||
default:
|
||||
Debug(DPROC,
|
||||
("[%ld] sigchld...pid #%ld died, stat=%d\n",
|
||||
(long) getpid(), (long) pid, WEXITSTATUS(waiter)));
|
||||
break;
|
||||
}
|
||||
} while (pid > 0);
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char *argv[]) {
|
||||
int argch;
|
||||
|
||||
while (-1 != (argch = getopt(argc, argv, "hnfpsiPx:m:cV"))) {
|
||||
switch (argch) {
|
||||
case 'x':
|
||||
if (!set_debug_flags(optarg))
|
||||
usage();
|
||||
break;
|
||||
case 'n':
|
||||
case 'f':
|
||||
NoFork = 1;
|
||||
break;
|
||||
case 'p':
|
||||
PermitAnyCrontab = 1;
|
||||
break;
|
||||
case 's':
|
||||
SyslogOutput = 1;
|
||||
break;
|
||||
case 'i':
|
||||
DisableInotify = 1;
|
||||
break;
|
||||
case 'P':
|
||||
ChangePath = 0;
|
||||
break;
|
||||
case 'm':
|
||||
strncpy(MailCmd, optarg, MAX_COMMAND);
|
||||
break;
|
||||
case 'c':
|
||||
EnableClustering = 1;
|
||||
break;
|
||||
case 'V':
|
||||
puts(PACKAGE_STRING);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
435
src/cronnext.c
Normal file
435
src/cronnext.c
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
cronnext - calculate the time cron will execute the next job
|
||||
Copyright (C) 2016 Marco Migliori <sgerwk@aol.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The GNU General Public License can also be found in the file
|
||||
`COPYING' that comes with the Anacron source distribution.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define MAIN_PROGRAM
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "funcs.h"
|
||||
#include "cron-paths.h"
|
||||
|
||||
/* flags to crontab search */
|
||||
#define ENTRIES 0x01 // print entries
|
||||
#define CRONTABS 0x02 // print crontabs
|
||||
#define SYSTEM 0x04 // include system crontab
|
||||
#define ALLJOBS 0x08 // print all jobs in interval
|
||||
|
||||
#ifdef WITH_INOTIFY
|
||||
void set_cron_watched(int fd) {
|
||||
/* empty stub */
|
||||
(void)fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_command(entry *e, user *u) {
|
||||
/* empty stub */
|
||||
(void)e;
|
||||
(void)u;
|
||||
}
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
int get_security_context(const char *name, int crontab_fd,
|
||||
security_context_t *rcontext, const char *tabname) {
|
||||
/* empty stub */
|
||||
(void)name;
|
||||
(void)crontab_fd;
|
||||
(void)tabname;
|
||||
*rcontext = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_security_context(security_context_t *scontext) {
|
||||
/* empty stub */
|
||||
(void)scontext;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* print entry flags
|
||||
*/
|
||||
const char *flagname[]= {
|
||||
"MIN_STAR",
|
||||
"HR_STAR",
|
||||
"DOM_STAR",
|
||||
"DOW_STAR",
|
||||
"WHEN_REBOOT",
|
||||
"DONT_LOG"
|
||||
};
|
||||
|
||||
void printflags(char *indent, int flags) {
|
||||
size_t f;
|
||||
int first = 1;
|
||||
|
||||
printf("%s flagnames:", indent);
|
||||
for (f = 0; f < sizeof(flagname)/sizeof(char *); f++)
|
||||
if (flags & (int)1 << f) {
|
||||
printf("%s%s", first ? " " : "|", flagname[f]);
|
||||
first = 0;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* print a crontab entry
|
||||
*/
|
||||
void printentry(char *indent, entry *e, time_t next) {
|
||||
printf("%s - user: %s\n", indent, e->pwd->pw_name);
|
||||
printf("%s cmd: \"%s\"\n", indent, e->cmd);
|
||||
printf("%s flags: 0x%02X\n", indent, e->flags);
|
||||
printflags(indent, e->flags);
|
||||
printf("%s delay: %d\n", indent, e->delay);
|
||||
printf("%s next: %ld\n", indent, (long)next);
|
||||
printf("%s nextstring: ", indent);
|
||||
printf("%s", asctime(localtime(&next)));
|
||||
}
|
||||
|
||||
/*
|
||||
* print a crontab data
|
||||
*/
|
||||
void printcrontab(user *u) {
|
||||
printf(" - user: \"%s\"\n", u->name);
|
||||
printf(" crontab: %s\n", u->tabname);
|
||||
printf(" system: %d\n", u->system);
|
||||
printf(" entries:\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* basic algorithm: iterate over time from now to 8 year ahead in default steps
|
||||
* of 1 minute, checking whether time matches a crontab entry at each step (8
|
||||
* years is the largest interval between two crontab matches)
|
||||
*
|
||||
* to save iterations, use larger steps if month or day don't match the entry:
|
||||
* - if the month doesn't match, skip to 00:00 of the first day of next month
|
||||
* - for the day, avoid the complication of the different length of months: if
|
||||
* neither the day nor the next day match, increase time of one day
|
||||
*/
|
||||
|
||||
/*
|
||||
* check whether time matches day of month and/or day of week; this requires
|
||||
* checking dom if dow=*, dow if dom=*, either one otherwise; see comment "the
|
||||
* dom/dow situation is odd..." in cron.c
|
||||
*/
|
||||
int matchday(entry *e, time_t time) {
|
||||
struct tm current;
|
||||
|
||||
localtime_r(&time, ¤t);
|
||||
|
||||
if (e->flags & DOW_STAR)
|
||||
return bit_test(e->dom, current.tm_mday - 1);
|
||||
if (e->flags & DOM_STAR)
|
||||
return bit_test(e->dow, current.tm_wday);
|
||||
return bit_test(e->dom, current.tm_mday - 1) ||
|
||||
bit_test(e->dow, current.tm_wday);
|
||||
}
|
||||
|
||||
/*
|
||||
* next time matching a crontab entry
|
||||
*/
|
||||
time_t nextmatch(entry *e, time_t start, time_t end) {
|
||||
time_t time;
|
||||
struct tm current;
|
||||
|
||||
for (time = start; time <= end; ) {
|
||||
localtime_r(&time, ¤t);
|
||||
|
||||
/* month doesn't match: move to 1st of next month */
|
||||
if (!bit_test(e->month, current.tm_mon)) {
|
||||
current.tm_mon++;
|
||||
if (current.tm_mon >= 12) {
|
||||
current.tm_year++;
|
||||
current.tm_mon = 0;
|
||||
}
|
||||
current.tm_mday = 1;
|
||||
current.tm_hour = 0;
|
||||
current.tm_min = 0;
|
||||
time = mktime(¤t);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* neither time nor time+1day match day: increase 1 day */
|
||||
if (!matchday(e, time) && !matchday(e, time + 24 * 60 * 60)) {
|
||||
time += 24 * 60 * 60;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if time matches, return time;
|
||||
* check for month is redudant, but check for day is
|
||||
* necessary because we only know that either time
|
||||
* or time+1day match */
|
||||
if (bit_test(e->month, current.tm_mon) &&
|
||||
matchday(e, time) &&
|
||||
bit_test(e->hour, current.tm_hour) &&
|
||||
bit_test(e->minute, current.tm_min)
|
||||
)
|
||||
return time;
|
||||
|
||||
/* skip to next minute */
|
||||
time += 60;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* match a user against a list
|
||||
*/
|
||||
int matchuser(char *user_name, char *list) {
|
||||
char *pos;
|
||||
size_t l = strlen(user_name);
|
||||
|
||||
for (pos = list; (pos = strstr(pos, user_name)) != NULL; pos += l) {
|
||||
if ((pos != list) && (*(pos - 1) != ','))
|
||||
continue;
|
||||
if ((pos[l] != '\0') && (pos[l] != ','))
|
||||
continue;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* find next sheduled job
|
||||
*/
|
||||
time_t cronnext(cron_db database,
|
||||
time_t start, time_t end,
|
||||
char *include, char *exclude, char *command, int flags) {
|
||||
time_t closest, next;
|
||||
user *u;
|
||||
entry *e;
|
||||
char *indent = "";
|
||||
|
||||
if (flags & CRONTABS) {
|
||||
printf("crontabs:\n");
|
||||
indent = " ";
|
||||
}
|
||||
else if (flags & ALLJOBS)
|
||||
printf("jobs:\n");
|
||||
|
||||
/* find next sheduled time */
|
||||
closest = -1;
|
||||
for (u = database.head; u; u = u->next) {
|
||||
if (include && !matchuser(u->name, include))
|
||||
continue;
|
||||
if (exclude && matchuser(u->name, exclude))
|
||||
continue;
|
||||
if (!(flags & SYSTEM) && u->system)
|
||||
continue;
|
||||
|
||||
if (flags & CRONTABS)
|
||||
printcrontab(u);
|
||||
|
||||
for (e = u->crontab; e; e = e->next) {
|
||||
if (command && strstr(e->cmd, command) == NULL)
|
||||
continue;
|
||||
for (next = nextmatch(e, start, end);
|
||||
next <= end;
|
||||
next = nextmatch(e, next + 60, end)) {
|
||||
if (next < 0)
|
||||
break;
|
||||
if (closest < 0 || next < closest)
|
||||
closest = next;
|
||||
if (flags & ENTRIES)
|
||||
printentry(indent, e, next);
|
||||
if (! (flags & ALLJOBS))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
/*
|
||||
* load installed crontabs and/or crontab files
|
||||
*/
|
||||
cron_db database(int installed, char **additional) {
|
||||
cron_db db = {NULL, NULL, (time_t) 0};
|
||||
struct passwd pw;
|
||||
int fd;
|
||||
struct stat ss;
|
||||
user *u;
|
||||
|
||||
if (installed)
|
||||
load_database(&db);
|
||||
|
||||
for ( ; *additional != NULL; additional++) {
|
||||
fd = open(*additional, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror(*additional);
|
||||
continue;
|
||||
}
|
||||
fstat(fd, &ss);
|
||||
if (S_ISDIR(ss.st_mode)) {
|
||||
fprintf(stderr, "%s is a directory - skipping\n", *additional);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
pw.pw_name = *additional;
|
||||
pw.pw_passwd = "";
|
||||
pw.pw_dir = ".";
|
||||
u = load_user(fd, &pw, *additional, *additional, *additional);
|
||||
if (u == NULL) {
|
||||
printf("cannot load crontab %s\n", *additional);
|
||||
continue;
|
||||
}
|
||||
link_user(&db, u);
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void usage() {
|
||||
fprintf(stderr, "Find the time of the next scheduled cron job.\n");
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, " cronnext [options] [file ...]\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -i users include only the crontab of these users\n");
|
||||
fprintf(stderr, " -e users exclude the crontab of these users\n");
|
||||
fprintf(stderr, " -s do not include the system crontab\n");
|
||||
fprintf(stderr, " -a examine installed crontabs even if files are given\n");
|
||||
fprintf(stderr, " -t time start from this time (seconds since epoch)\n");
|
||||
fprintf(stderr, " -q time end check at this time (seconds since epoch)\n");
|
||||
fprintf(stderr, " -j cmd only check jobs that contain cmd as a substring\n");
|
||||
fprintf(stderr, " -l print next jobs to be executed\n");
|
||||
fprintf(stderr, " -c print next execution of each job\n");
|
||||
fprintf(stderr, " -f print all jobs executed in the given interval\n");
|
||||
fprintf(stderr, " -h this help\n");
|
||||
fprintf(stderr, " -V print version and exit\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* main
|
||||
*/
|
||||
int main(int argn, char *argv[]) {
|
||||
int opt;
|
||||
char *include, *exclude, *command;
|
||||
int flags;
|
||||
time_t start, next, end = 0;
|
||||
int endtime, printjobs;
|
||||
cron_db db;
|
||||
int installed = 0;
|
||||
|
||||
include = NULL;
|
||||
exclude = NULL;
|
||||
command = NULL;
|
||||
flags = SYSTEM;
|
||||
endtime = 0;
|
||||
printjobs = 0;
|
||||
start = time(NULL) / 60 * 60;
|
||||
|
||||
while (-1 != (opt = getopt(argn, argv, "i:e:ast:q:j:lcfhV"))) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
include = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
exclude = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
installed = 1;
|
||||
break;
|
||||
case 's':
|
||||
flags &= ~SYSTEM;
|
||||
break;
|
||||
case 't':
|
||||
start = atoi(optarg) / 60 * 60;
|
||||
break;
|
||||
case 'q':
|
||||
end = atoi(optarg) / 60 * 60;
|
||||
endtime = 1;
|
||||
break;
|
||||
case 'j':
|
||||
command = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
printjobs = 1;
|
||||
break;
|
||||
case 'c':
|
||||
flags |= ENTRIES | CRONTABS;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= ALLJOBS | ENTRIES;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
case 'V':
|
||||
puts(PACKAGE_STRING);
|
||||
return EXIT_SUCCESS;
|
||||
default:
|
||||
fprintf(stderr, "unrecognized option: %s\n",
|
||||
argv[optind - 1]);
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ALLJOBS && !endtime) {
|
||||
fprintf(stderr, "no ending time specified: -f requires -q\n");
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* maximum match interval is 8 years:
|
||||
* crontab has '* * 29 2 *' and we are on 1 March 2096:
|
||||
* next matching time will be 29 February 2104 */
|
||||
if (!endtime)
|
||||
end = start + 8 * 12 * 31 * 24 * 60 * 60;
|
||||
|
||||
/* debug cron */
|
||||
if (flags & CRONTABS) {
|
||||
printf("spool: %s\n", SPOOL_DIR);
|
||||
set_debug_flags("");
|
||||
}
|
||||
/* "load,pars" for debugging loading and parsing, "" for nothing
|
||||
see globals.h for symbolic names and macros.h for meaning */
|
||||
|
||||
/* load database */
|
||||
db = database(installed || argv[optind] == NULL, argv + optind);
|
||||
|
||||
/* find time of next scheduled command */
|
||||
next = cronnext(db, start, end, include, exclude, command, flags);
|
||||
|
||||
/* print time */
|
||||
if (next == -1)
|
||||
return EXIT_FAILURE;
|
||||
else
|
||||
printf("next: %ld\n", (long) next);
|
||||
|
||||
/* print next jobs */
|
||||
if (printjobs) {
|
||||
printf("nextjobs:\n");
|
||||
cronnext(db, next, next, include, exclude, command, (flags & SYSTEM) | ENTRIES);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
1119
src/crontab.c
Normal file
1119
src/crontab.c
Normal file
File diff suppressed because it is too large
Load Diff
682
src/database.c
Normal file
682
src/database.c
Normal file
@ -0,0 +1,682 @@
|
||||
/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* vix 26jan87 [RCS has the log]
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified 2010/09/12 by Colin Dean, Durham University IT Service,
|
||||
* to add clustering support.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef WITH_INOTIFY
|
||||
# include <sys/inotify.h>
|
||||
#endif
|
||||
|
||||
#include "funcs.h"
|
||||
#include "globals.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
/* size of the event structure, not counting name */
|
||||
#define EVENT_SIZE (sizeof (struct inotify_event))
|
||||
|
||||
/* reasonable guess as to size of 1024 events */
|
||||
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
|
||||
|
||||
static void overwrite_database(cron_db *, cron_db *);
|
||||
|
||||
static void process_crontab(const char *, const char *,
|
||||
const char *, cron_db *, cron_db *);
|
||||
|
||||
static int not_a_crontab(DIR_T * dp);
|
||||
/* return 1 if we should skip this file */
|
||||
|
||||
static void max_mtime(const char *dir_name, struct stat *max_st);
|
||||
/* record max mtime of any file under dir_name in max_st */
|
||||
|
||||
static int
|
||||
check_open(const char *tabname, const char *uname,
|
||||
struct passwd *pw, time_t * mtime) {
|
||||
struct stat statbuf;
|
||||
int crontab_fd;
|
||||
pid_t pid = getpid();
|
||||
|
||||
if ((crontab_fd =
|
||||
open(tabname, O_RDONLY | O_NONBLOCK, 0)) == -1) {
|
||||
log_it(uname, pid, "CAN'T OPEN", tabname, errno);
|
||||
return (-1);
|
||||
}
|
||||
if (fstat(crontab_fd, &statbuf) < OK) {
|
||||
log_it(uname, pid, "STAT FAILED", tabname, errno);
|
||||
close(crontab_fd);
|
||||
return (-1);
|
||||
}
|
||||
*mtime = statbuf.st_mtime;
|
||||
if (PermitAnyCrontab == 0) {
|
||||
if (!S_ISREG(statbuf.st_mode)) {
|
||||
log_it(uname, pid, "NOT REGULAR", tabname, 0);
|
||||
close(crontab_fd);
|
||||
return (-1);
|
||||
}
|
||||
if ((statbuf.st_mode & 07533) != 0400) {
|
||||
log_it(uname, pid, "BAD FILE MODE", tabname, 0);
|
||||
close(crontab_fd);
|
||||
return (-1);
|
||||
}
|
||||
if (statbuf.st_uid != ROOT_UID && (pw == NULL ||
|
||||
statbuf.st_uid != pw->pw_uid ||
|
||||
strcmp(uname, pw->pw_name) != 0)) {
|
||||
log_it(uname, pid, "WRONG FILE OWNER", tabname, 0);
|
||||
close(crontab_fd);
|
||||
return (-1);
|
||||
}
|
||||
if (pw && statbuf.st_nlink != 1) {
|
||||
log_it(uname, pid, "BAD LINK COUNT", tabname, 0);
|
||||
close(crontab_fd);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
return (crontab_fd);
|
||||
}
|
||||
|
||||
static orphan *orphans;
|
||||
|
||||
static void
|
||||
free_orphan(orphan *o) {
|
||||
free(o->tabname);
|
||||
free(o->fname);
|
||||
free(o->uname);
|
||||
free(o);
|
||||
}
|
||||
|
||||
void
|
||||
check_orphans(cron_db *db) {
|
||||
orphan *prev_orphan = NULL;
|
||||
orphan *o = orphans;
|
||||
|
||||
while (o != NULL) {
|
||||
if (getpwnam(o->uname) != NULL) {
|
||||
orphan *next = o->next;
|
||||
|
||||
if (prev_orphan == NULL) {
|
||||
orphans = next;
|
||||
} else {
|
||||
prev_orphan->next = next;
|
||||
}
|
||||
|
||||
process_crontab(o->uname, o->fname, o->tabname,
|
||||
db, NULL);
|
||||
|
||||
/* process_crontab could have added a new orphan */
|
||||
if (prev_orphan == NULL && orphans != next) {
|
||||
prev_orphan = orphans;
|
||||
}
|
||||
free_orphan(o);
|
||||
o = next;
|
||||
} else {
|
||||
prev_orphan = o;
|
||||
o = o->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
find_orphan(const char *uname, const char *fname, const char *tabname) {
|
||||
orphan *o;
|
||||
|
||||
for (o = orphans; o != NULL; o = o->next) {
|
||||
if (uname && o->uname) {
|
||||
if (strcmp(uname, o->uname) != 0)
|
||||
continue;
|
||||
} else if (uname != o->uname)
|
||||
continue;
|
||||
|
||||
if (fname && o->fname) {
|
||||
if (strcmp(fname, o->fname) != 0)
|
||||
continue;
|
||||
} else if (fname != o->fname)
|
||||
continue;
|
||||
|
||||
if (tabname && o->tabname) {
|
||||
if (strcmp(tabname, o->tabname) != 0)
|
||||
continue;
|
||||
} else if (tabname != o->tabname)
|
||||
continue;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_orphan(const char *uname, const char *fname, const char *tabname) {
|
||||
orphan *o;
|
||||
|
||||
if (find_orphan(uname, fname, tabname))
|
||||
return;
|
||||
|
||||
o = calloc(1, sizeof(*o));
|
||||
if (o == NULL)
|
||||
return;
|
||||
|
||||
if (uname)
|
||||
if ((o->uname=strdup(uname)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (fname)
|
||||
if ((o->fname=strdup(fname)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (tabname)
|
||||
if ((o->tabname=strdup(tabname)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
o->next = orphans;
|
||||
orphans = o;
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
free_orphan(o);
|
||||
}
|
||||
|
||||
static void
|
||||
process_crontab(const char *uname, const char *fname, const char *tabname,
|
||||
cron_db * new_db, cron_db * old_db) {
|
||||
struct passwd *pw = NULL;
|
||||
int crontab_fd = -1;
|
||||
user *u = NULL;
|
||||
time_t mtime;
|
||||
int crond_crontab = (fname == NULL) && (strcmp(tabname, SYSCRONTAB) != 0);
|
||||
|
||||
if (fname == NULL) {
|
||||
/* must be set to something for logging purposes.
|
||||
*/
|
||||
fname = "*system*";
|
||||
}
|
||||
else if ((pw = getpwnam(uname)) == NULL) {
|
||||
/* file doesn't have a user in passwd file.
|
||||
*/
|
||||
log_it(uname, getpid(), "ORPHAN", "no passwd entry", 0);
|
||||
add_orphan(uname, fname, tabname);
|
||||
|
||||
goto next_crontab;
|
||||
}
|
||||
|
||||
if ((crontab_fd = check_open(tabname, uname, pw, &mtime)) == -1)
|
||||
goto next_crontab;
|
||||
|
||||
mtime = TMIN(new_db->mtime, mtime);
|
||||
|
||||
Debug(DLOAD, ("\t%s:", fname));
|
||||
|
||||
if (old_db != NULL)
|
||||
u = find_user(old_db, fname, crond_crontab ? tabname : NULL); /* find user in old_db */
|
||||
|
||||
if (u != NULL) {
|
||||
/* if crontab has not changed since we last read it
|
||||
* in, then we can just use our existing entry.
|
||||
*/
|
||||
if (u->mtime == mtime) {
|
||||
Debug(DLOAD, (" [no change, using old data]"));
|
||||
unlink_user(old_db, u);
|
||||
link_user(new_db, u);
|
||||
goto next_crontab;
|
||||
}
|
||||
|
||||
/* before we fall through to the code that will reload
|
||||
* the user, let's deallocate and unlink the user in
|
||||
* the old database. This is more a point of memory
|
||||
* efficiency than anything else, since all leftover
|
||||
* users will be deleted from the old database when
|
||||
* we finish with the crontab...
|
||||
*/
|
||||
Debug(DLOAD, (" [delete old data]"));
|
||||
unlink_user(old_db, u);
|
||||
free_user(u);
|
||||
log_it(fname, getpid(), "RELOAD", tabname, 0);
|
||||
}
|
||||
|
||||
u = load_user(crontab_fd, pw, uname, fname, tabname); /* read the file */
|
||||
crontab_fd = -1; /* load_user takes care of closing the file */
|
||||
if (u != NULL) {
|
||||
u->mtime = mtime;
|
||||
link_user(new_db, u);
|
||||
}
|
||||
|
||||
next_crontab:
|
||||
if (crontab_fd != -1) {
|
||||
Debug(DLOAD, (" [done]\n"));
|
||||
close(crontab_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cluster_host_is_local(void)
|
||||
{
|
||||
char filename[NAME_MAX+1];
|
||||
int is_local;
|
||||
FILE *f;
|
||||
char hostname[MAXHOSTNAMELEN], myhostname[MAXHOSTNAMELEN];
|
||||
|
||||
if (!EnableClustering)
|
||||
return (1);
|
||||
|
||||
/* to allow option of NFS-mounting SPOOL_DIR on a cluster of
|
||||
* hosts and to only use crontabs here on any one host at a
|
||||
* time, allow for existence of a CRON_HOSTNAME file, and if
|
||||
* it doesn't exist, or exists but does not contain this
|
||||
* host's hostname, then skip the crontabs.
|
||||
*
|
||||
* Note: for safety's sake, no CRON_HOSTNAME file means skip,
|
||||
* otherwise its accidental deletion could result in multiple
|
||||
* cluster hosts running the same cron jobs, which is
|
||||
* potentially worse.
|
||||
*/
|
||||
|
||||
is_local = 0;
|
||||
if (glue_strings(filename, sizeof filename, SPOOL_DIR, CRON_HOSTNAME, '/')) {
|
||||
if ((f = fopen(filename, "r"))) {
|
||||
|
||||
if (EOF != get_string(hostname, MAXHOSTNAMELEN, f, "\n") &&
|
||||
gethostname(myhostname, MAXHOSTNAMELEN) == 0) {
|
||||
is_local = (strcmp(myhostname, hostname) == 0);
|
||||
} else {
|
||||
Debug(DLOAD, ("cluster: hostname comparison error\n"));
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
} else {
|
||||
Debug(DLOAD, ("cluster: file %s not found\n", filename));
|
||||
}
|
||||
}
|
||||
|
||||
return (is_local);
|
||||
}
|
||||
|
||||
#if defined WITH_INOTIFY
|
||||
void check_inotify_database(cron_db * old_db) {
|
||||
cron_db new_db;
|
||||
DIR_T *dp;
|
||||
DIR *dir;
|
||||
struct timeval tv;
|
||||
fd_set rfds;
|
||||
int retval;
|
||||
char buf[BUF_LEN];
|
||||
pid_t pid = getpid();
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(old_db->ifd, &rfds);
|
||||
|
||||
retval = select(old_db->ifd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (retval == -1) {
|
||||
if (errno != EINTR)
|
||||
log_it("CRON", pid, "INOTIFY", "select failed", errno);
|
||||
return;
|
||||
}
|
||||
else if (FD_ISSET(old_db->ifd, &rfds)) {
|
||||
new_db.head = new_db.tail = NULL;
|
||||
new_db.ifd = old_db->ifd;
|
||||
new_db.mtime = time(NULL) - 1;
|
||||
while ((retval = (int)read(old_db->ifd, buf, sizeof (buf))) == -1 &&
|
||||
errno == EINTR) ;
|
||||
|
||||
if (retval == 0) {
|
||||
/* this should not happen as the buffer is large enough */
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
if (retval <= 0) {
|
||||
log_it("CRON", pid, "INOTIFY", "read failed", errno);
|
||||
/* something fatal must have occurred we have no other reasonable
|
||||
* way how to handle this failure than exit.
|
||||
*/
|
||||
(void) exit(ERROR_EXIT);
|
||||
}
|
||||
|
||||
/* we must reinstate the watches here - TODO reinstate only watches
|
||||
* which get IN_IGNORED event
|
||||
*/
|
||||
set_cron_watched(old_db->ifd);
|
||||
|
||||
/* TODO: parse the events and read only affected files */
|
||||
#if defined ENABLE_SYSCRONTAB
|
||||
process_crontab("root", NULL, SYSCRONTAB, &new_db, old_db);
|
||||
#endif
|
||||
|
||||
if (!(dir = opendir(SYS_CROND_DIR))) {
|
||||
log_it("CRON", pid, "OPENDIR FAILED", SYS_CROND_DIR, errno);
|
||||
}
|
||||
else {
|
||||
while (NULL != (dp = readdir(dir))) {
|
||||
char tabname[NAME_MAX + 1];
|
||||
|
||||
if (not_a_crontab(dp))
|
||||
continue;
|
||||
|
||||
if (!glue_strings(tabname, sizeof tabname, SYS_CROND_DIR,
|
||||
dp->d_name, '/'))
|
||||
continue;
|
||||
process_crontab("root", NULL, tabname, &new_db, old_db);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
if (!(dir = opendir(SPOOL_DIR))) {
|
||||
log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
|
||||
}
|
||||
else {
|
||||
while (NULL != (dp = readdir(dir))) {
|
||||
char fname[NAME_MAX + 1], tabname[NAME_MAX + 1];
|
||||
|
||||
if (not_a_crontab(dp))
|
||||
continue;
|
||||
|
||||
strncpy(fname, dp->d_name, NAME_MAX + 1);
|
||||
|
||||
if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR,
|
||||
dp->d_name, '/'))
|
||||
continue;
|
||||
process_crontab(fname, fname, tabname, &new_db, old_db);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/* if we don't do this, then when our children eventually call
|
||||
* getpwnam() in do_command.c's child_process to verify MAILTO=,
|
||||
* they will screw us up (and v-v).
|
||||
*/
|
||||
endpwent();
|
||||
}
|
||||
else {
|
||||
/* just return as no db reload is needed */
|
||||
return;
|
||||
}
|
||||
|
||||
overwrite_database(old_db, &new_db);
|
||||
Debug(DLOAD, ("check_inotify_database is done\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void overwrite_database(cron_db * old_db, cron_db * new_db) {
|
||||
user *u, *nu;
|
||||
/* whatever's left in the old database is now junk.
|
||||
*/
|
||||
Debug(DLOAD, ("unlinking old database:\n"));
|
||||
for (u = old_db->head; u != NULL; u = nu) {
|
||||
Debug(DLOAD, ("\t%s\n", u->name));
|
||||
nu = u->next;
|
||||
unlink_user(old_db, u);
|
||||
free_user(u);
|
||||
}
|
||||
|
||||
/* overwrite the database control block with the new one.
|
||||
*/
|
||||
*old_db = *new_db;
|
||||
}
|
||||
|
||||
int load_database(cron_db * old_db) {
|
||||
struct stat statbuf, syscron_stat, crond_stat;
|
||||
cron_db new_db;
|
||||
DIR_T *dp;
|
||||
DIR *dir;
|
||||
pid_t pid = getpid();
|
||||
int is_local = 0;
|
||||
time_t now;
|
||||
|
||||
Debug(DLOAD, ("[%ld] load_database()\n", (long) pid));
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
/* before we start loading any data, do a stat on SPOOL_DIR
|
||||
* so that if anything changes as of this moment (i.e., before we've
|
||||
* cached any of the database), we'll see the changes next time.
|
||||
*/
|
||||
if (stat(SPOOL_DIR, &statbuf) < OK) {
|
||||
log_it("CRON", pid, "STAT FAILED", SPOOL_DIR, errno);
|
||||
statbuf.st_mtime = 0;
|
||||
}
|
||||
else {
|
||||
max_mtime(SPOOL_DIR, &statbuf);
|
||||
}
|
||||
|
||||
if (stat(SYS_CROND_DIR, &crond_stat) < OK) {
|
||||
log_it("CRON", pid, "STAT FAILED", SYS_CROND_DIR, errno);
|
||||
crond_stat.st_mtime = 0;
|
||||
}
|
||||
else {
|
||||
max_mtime(SYS_CROND_DIR, &crond_stat);
|
||||
}
|
||||
|
||||
#if defined ENABLE_SYSCRONTAB
|
||||
/* track system crontab file
|
||||
*/
|
||||
if (stat(SYSCRONTAB, &syscron_stat) < OK)
|
||||
syscron_stat.st_mtime = 0;
|
||||
#endif
|
||||
|
||||
/* if spooldir's mtime has not changed, we don't need to fiddle with
|
||||
* the database.
|
||||
*
|
||||
* Note that old_db->mtime is initialized to 0 in main().
|
||||
*
|
||||
* We also use now - 1 as the upper bound of timestamp to avoid race,
|
||||
* when a crontab is updated twice in a single second when we are
|
||||
* just reading it.
|
||||
*/
|
||||
if (old_db->mtime != 0
|
||||
&& old_db->mtime == TMIN(now - 1,
|
||||
TMAX(crond_stat.st_mtime,
|
||||
TMAX(statbuf.st_mtime, syscron_stat.st_mtime)))
|
||||
) {
|
||||
Debug(DLOAD, ("[%ld] spool dir mtime unch, no load needed.\n",
|
||||
(long) pid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* something's different. make a new database, moving unchanged
|
||||
* elements from the old database, reloading elements that have
|
||||
* actually changed. Whatever is left in the old database when
|
||||
* we're done is chaff -- crontabs that disappeared.
|
||||
*/
|
||||
new_db.mtime = now - 1;
|
||||
new_db.head = new_db.tail = NULL;
|
||||
#if defined WITH_INOTIFY
|
||||
new_db.ifd = old_db->ifd;
|
||||
#endif
|
||||
|
||||
#if defined ENABLE_SYSCRONTAB
|
||||
if (syscron_stat.st_mtime)
|
||||
process_crontab("root", NULL, SYSCRONTAB, &new_db, old_db);
|
||||
#endif
|
||||
|
||||
if (!(dir = opendir(SYS_CROND_DIR))) {
|
||||
log_it("CRON", pid, "OPENDIR FAILED", SYS_CROND_DIR, errno);
|
||||
}
|
||||
else {
|
||||
while (NULL != (dp = readdir(dir))) {
|
||||
char tabname[NAME_MAX + 1];
|
||||
|
||||
if (not_a_crontab(dp))
|
||||
continue;
|
||||
|
||||
if (!glue_strings(tabname, sizeof tabname, SYS_CROND_DIR,
|
||||
dp->d_name, '/'))
|
||||
continue; /* XXX log? */
|
||||
|
||||
process_crontab("root", NULL, tabname, &new_db, old_db);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/* we used to keep this dir open all the time, for the sake of
|
||||
* efficiency. however, we need to close it in every fork, and
|
||||
* we fork a lot more often than the mtime of the dir changes.
|
||||
*/
|
||||
|
||||
if (!(dir = opendir(SPOOL_DIR))) {
|
||||
log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
|
||||
}
|
||||
else {
|
||||
|
||||
is_local = cluster_host_is_local();
|
||||
|
||||
while (is_local && NULL != (dp = readdir(dir))) {
|
||||
char fname[NAME_MAX + 1], tabname[NAME_MAX + 1];
|
||||
|
||||
if (not_a_crontab(dp))
|
||||
continue;
|
||||
|
||||
strncpy(fname, dp->d_name, NAME_MAX);
|
||||
fname[NAME_MAX] = '\0';
|
||||
|
||||
if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, fname, '/'))
|
||||
continue; /* XXX log? */
|
||||
|
||||
process_crontab(fname, fname, tabname, &new_db, old_db);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/* if we don't do this, then when our children eventually call
|
||||
* getpwnam() in do_command.c's child_process to verify MAILTO=,
|
||||
* they will screw us up (and v-v).
|
||||
*/
|
||||
endpwent();
|
||||
|
||||
overwrite_database(old_db, &new_db);
|
||||
Debug(DLOAD, ("load_database is done\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void link_user(cron_db * db, user * u) {
|
||||
if (db->head == NULL)
|
||||
db->head = u;
|
||||
if (db->tail)
|
||||
db->tail->next = u;
|
||||
u->prev = db->tail;
|
||||
u->next = NULL;
|
||||
db->tail = u;
|
||||
}
|
||||
|
||||
void unlink_user(cron_db * db, user * u) {
|
||||
if (u->prev == NULL)
|
||||
db->head = u->next;
|
||||
else
|
||||
u->prev->next = u->next;
|
||||
|
||||
if (u->next == NULL)
|
||||
db->tail = u->prev;
|
||||
else
|
||||
u->next->prev = u->prev;
|
||||
}
|
||||
|
||||
user *find_user(cron_db * db, const char *name, const char *tabname) {
|
||||
user *u;
|
||||
|
||||
for (u = db->head; u != NULL; u = u->next)
|
||||
if ((strcmp(u->name, name) == 0)
|
||||
&& ((tabname == NULL)
|
||||
|| (strcmp(tabname, u->tabname) == 0)
|
||||
)
|
||||
)
|
||||
break;
|
||||
return (u);
|
||||
}
|
||||
|
||||
static int not_a_crontab(DIR_T * dp) {
|
||||
size_t len;
|
||||
|
||||
/* avoid file names beginning with ".". this is good
|
||||
* because we would otherwise waste two guaranteed calls
|
||||
* to getpwnam() for . and .., and there shouldn't be
|
||||
* hidden files in here anyway
|
||||
*/
|
||||
if (dp->d_name[0] == '.')
|
||||
return (1);
|
||||
|
||||
/* ignore files starting with # and ending with ~ */
|
||||
if (dp->d_name[0] == '#')
|
||||
return (1);
|
||||
|
||||
/* ignore CRON_HOSTNAME file (in case doesn't start with ".") */
|
||||
if (0 == strcmp(dp->d_name, CRON_HOSTNAME))
|
||||
return(1);
|
||||
|
||||
len = strlen(dp->d_name);
|
||||
|
||||
if (len >= NAME_MAX || len == 0)
|
||||
return (1);
|
||||
|
||||
if (dp->d_name[len - 1] == '~')
|
||||
return (1);
|
||||
|
||||
if ((len > 8) && (strncmp(dp->d_name + len - 8, ".rpmsave", 8) == 0))
|
||||
return (1);
|
||||
if ((len > 8) && (strncmp(dp->d_name + len - 8, ".rpmorig", 8) == 0))
|
||||
return (1);
|
||||
if ((len > 7) && (strncmp(dp->d_name + len - 7, ".rpmnew", 7) == 0))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void max_mtime(const char *dir_name, struct stat *max_st) {
|
||||
DIR *dir;
|
||||
DIR_T *dp;
|
||||
struct stat st;
|
||||
|
||||
if (!(dir = opendir(dir_name))) {
|
||||
max_st->st_mtime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
while (NULL != (dp = readdir(dir))) {
|
||||
char tabname[NAME_MAX + 1];
|
||||
|
||||
if ( not_a_crontab ( dp ) && strcmp(dp->d_name, CRON_HOSTNAME) != 0)
|
||||
continue;
|
||||
|
||||
if (!glue_strings(tabname, sizeof tabname, dir_name, dp->d_name, '/'))
|
||||
continue; /* XXX log? */
|
||||
|
||||
if (stat(tabname, &st) < OK)
|
||||
continue; /* XXX log? */
|
||||
|
||||
if (st.st_mtime > max_st->st_mtime)
|
||||
max_st->st_mtime = st.st_mtime;
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
641
src/do_command.c
Normal file
641
src/do_command.c
Normal file
@ -0,0 +1,641 @@
|
||||
/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "externs.h"
|
||||
#include "funcs.h"
|
||||
#include "globals.h"
|
||||
#include "structs.h"
|
||||
#include "cronie_common.h"
|
||||
|
||||
#ifndef isascii
|
||||
# define isascii(c) ((unsigned)(c)<=0177)
|
||||
#endif
|
||||
|
||||
static int child_process(entry *, char **);
|
||||
static int safe_p(const char *, const char *);
|
||||
|
||||
void do_command(entry * e, user * u) {
|
||||
pid_t pid = getpid();
|
||||
int ev;
|
||||
char **jobenv = NULL;
|
||||
|
||||
Debug(DPROC, ("[%ld] do_command(%s, (%s,%ld,%ld))\n",
|
||||
(long) pid, e->cmd, u->name,
|
||||
(long) e->pwd->pw_uid, (long) e->pwd->pw_gid));
|
||||
|
||||
/* fork to become asynchronous -- parent process is done immediately,
|
||||
* and continues to run the normal cron code, which means return to
|
||||
* tick(). the child and grandchild don't leave this function, alive.
|
||||
*
|
||||
* vfork() is unsuitable, since we have much to do, and the parent
|
||||
* needs to be able to run off and fork other processes.
|
||||
*/
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
log_it("CRON", pid, "CAN'T FORK", "do_command", errno);
|
||||
break;
|
||||
case 0:
|
||||
/* child process */
|
||||
acquire_daemonlock(1);
|
||||
/* Set up the Red Hat security context for both mail/minder and job processes:
|
||||
*/
|
||||
if (cron_set_job_security_context(e, u, &jobenv) != 0) {
|
||||
_exit(ERROR_EXIT);
|
||||
}
|
||||
ev = child_process(e, jobenv);
|
||||
#ifdef WITH_PAM
|
||||
cron_close_pam();
|
||||
#endif
|
||||
env_free(jobenv);
|
||||
Debug(DPROC, ("[%ld] child process done, exiting\n", (long) getpid()));
|
||||
_exit(ev);
|
||||
break;
|
||||
default:
|
||||
/* parent process */
|
||||
break;
|
||||
}
|
||||
Debug(DPROC, ("[%ld] main process returning to work\n", (long) pid));
|
||||
}
|
||||
|
||||
static int child_process(entry * e, char **jobenv) {
|
||||
int stdin_pipe[2], stdout_pipe[2];
|
||||
char *input_data, *usernm, *mailto, *mailfrom;
|
||||
char mailto_expanded[MAX_EMAILSTR];
|
||||
char mailfrom_expanded[MAX_EMAILSTR];
|
||||
int children = 0;
|
||||
pid_t pid = getpid();
|
||||
struct sigaction sa;
|
||||
|
||||
/* Ignore SIGPIPE as we will be writing to pipes and do not want to terminate
|
||||
prematurely */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
/* our parent is watching for our death by catching SIGCHLD. we
|
||||
* do not care to watch for our children's deaths this way -- we
|
||||
* use wait() explicitly. so we have to reset the signal (which
|
||||
* was inherited from the parent).
|
||||
*/
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
|
||||
|
||||
Debug(DPROC, ("[%ld] child_process('%s')\n", (long) getpid(), e->cmd));
|
||||
#ifdef CAPITALIZE_FOR_PS
|
||||
/* mark ourselves as different to PS command watchers by upshifting
|
||||
* our program name. This has no effect on some kernels.
|
||||
*/
|
||||
/*local */ {
|
||||
char *pch;
|
||||
|
||||
for (pch = ProgramName; *pch; pch++)
|
||||
*pch = (char)MkUpper(*pch);
|
||||
}
|
||||
#endif /* CAPITALIZE_FOR_PS */
|
||||
|
||||
/* discover some useful and important environment settings
|
||||
*/
|
||||
usernm = e->pwd->pw_name;
|
||||
mailto = env_get("MAILTO", jobenv);
|
||||
mailfrom = env_get("MAILFROM", e->envp);
|
||||
|
||||
if (mailto != NULL) {
|
||||
if (expand_envvar(mailto, mailto_expanded, sizeof(mailto_expanded))) {
|
||||
mailto = mailto_expanded;
|
||||
}
|
||||
else {
|
||||
log_it("CRON", pid, "WARNING", "The environment variable 'MAILTO' could not be expanded. The non-expanded value will be used." , 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (mailfrom != NULL) {
|
||||
if (expand_envvar(mailfrom, mailfrom_expanded, sizeof(mailfrom_expanded))) {
|
||||
mailfrom = mailfrom_expanded;
|
||||
}
|
||||
else {
|
||||
log_it("CRON", pid, "WARNING", "The environment variable 'MAILFROM' could not be expanded. The non-expanded value will be used." , 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* create some pipes to talk to our future child
|
||||
*/
|
||||
if (pipe(stdin_pipe) == -1) { /* child's stdin */
|
||||
log_it("CRON", pid, "PIPE() FAILED", "stdin_pipe", errno);
|
||||
return ERROR_EXIT;
|
||||
}
|
||||
|
||||
if (pipe(stdout_pipe) == -1) { /* child's stdout */
|
||||
log_it("CRON", pid, "PIPE() FAILED", "stdout_pipe", errno);
|
||||
return ERROR_EXIT;
|
||||
}
|
||||
|
||||
/* since we are a forked process, we can diddle the command string
|
||||
* we were passed -- nobody else is going to use it again, right?
|
||||
*
|
||||
* if a % is present in the command, previous characters are the
|
||||
* command, and subsequent characters are the additional input to
|
||||
* the command. An escaped % will have the escape character stripped
|
||||
* from it. Subsequent %'s will be transformed into newlines,
|
||||
* but that happens later.
|
||||
*/
|
||||
/*local */ {
|
||||
int escaped = FALSE;
|
||||
int ch;
|
||||
char *p;
|
||||
|
||||
for (input_data = p = e->cmd;
|
||||
(ch = *input_data) != '\0'; input_data++, p++) {
|
||||
if (p != input_data)
|
||||
*p = (char)ch;
|
||||
if (escaped) {
|
||||
if (ch == '%')
|
||||
*--p = (char)ch;
|
||||
escaped = FALSE;
|
||||
continue;
|
||||
}
|
||||
if (ch == '\\') {
|
||||
escaped = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (ch == '%') {
|
||||
*input_data++ = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* fork again, this time so we can exec the user's command.
|
||||
*/
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
log_it("CRON", pid, "CAN'T FORK", "child_process", errno);
|
||||
return ERROR_EXIT;
|
||||
/*NOTREACHED*/
|
||||
case 0:
|
||||
Debug(DPROC, ("[%ld] grandchild process fork()'ed\n", (long) getpid()));
|
||||
|
||||
/* write a log message. we've waited this long to do it
|
||||
* because it was not until now that we knew the PID that
|
||||
* the actual user command shell was going to get and the
|
||||
* PID is part of the log message.
|
||||
*/
|
||||
if ((e->flags & DONT_LOG) == 0) {
|
||||
char *x = mkprints((u_char *) e->cmd, strlen(e->cmd));
|
||||
|
||||
if (x == NULL) /* out of memory, better exit */
|
||||
_exit(ERROR_EXIT);
|
||||
|
||||
log_it(usernm, getpid(), "CMD", x, 0);
|
||||
free(x);
|
||||
}
|
||||
|
||||
if (cron_change_user_permanently(e->pwd, env_get("HOME", jobenv)) < 0)
|
||||
_exit(ERROR_EXIT);
|
||||
|
||||
/* get new pgrp, void tty, etc.
|
||||
*/
|
||||
(void) setsid();
|
||||
|
||||
/* reset the SIGPIPE back to default so the child will terminate
|
||||
* if it tries to write to a closed pipe
|
||||
*/
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
/* close the pipe ends that we won't use. this doesn't affect
|
||||
* the parent, who has to read and write them; it keeps the
|
||||
* kernel from recording us as a potential client TWICE --
|
||||
* which would keep it from sending SIGPIPE in otherwise
|
||||
* appropriate circumstances.
|
||||
*/
|
||||
close(stdin_pipe[WRITE_PIPE]);
|
||||
close(stdout_pipe[READ_PIPE]);
|
||||
|
||||
/* grandchild process. make std{in,out} be the ends of
|
||||
* pipes opened by our daddy; make stderr go to stdout.
|
||||
*/
|
||||
if (stdin_pipe[READ_PIPE] != STDIN) {
|
||||
dup2(stdin_pipe[READ_PIPE], STDIN);
|
||||
close(stdin_pipe[READ_PIPE]);
|
||||
}
|
||||
if (stdout_pipe[WRITE_PIPE] != STDOUT) {
|
||||
dup2(stdout_pipe[WRITE_PIPE], STDOUT);
|
||||
close(stdout_pipe[WRITE_PIPE]);
|
||||
}
|
||||
dup2(STDOUT, STDERR);
|
||||
|
||||
/*
|
||||
* Exec the command.
|
||||
*/
|
||||
{
|
||||
char *shell = env_get("SHELL", jobenv);
|
||||
int fd, fdmax = TMIN(getdtablesize(), MAX_CLOSE_FD);
|
||||
|
||||
/* close all unwanted open file descriptors */
|
||||
for(fd = STDERR + 1; fd < fdmax; fd++) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#if DEBUGGING
|
||||
if (DebugFlags & DTEST) {
|
||||
fprintf(stderr, "debug DTEST is on, not exec'ing command.\n");
|
||||
fprintf(stderr, "\tcmd='%s' shell='%s'\n", e->cmd, shell);
|
||||
_exit(OK_EXIT);
|
||||
}
|
||||
#endif /*DEBUGGING*/
|
||||
execle(shell, shell, "-c", e->cmd, (char *) 0, jobenv);
|
||||
fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
|
||||
perror("execl");
|
||||
_exit(ERROR_EXIT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cron_restore_default_security_context();
|
||||
/* parent process */
|
||||
break;
|
||||
}
|
||||
|
||||
children++;
|
||||
|
||||
/* middle process, child of original cron, parent of process running
|
||||
* the user's command.
|
||||
*/
|
||||
|
||||
Debug(DPROC, ("[%ld] child continues, closing pipes\n", (long) getpid()));
|
||||
|
||||
/* close the ends of the pipe that will only be referenced in the
|
||||
* grandchild process...
|
||||
*/
|
||||
close(stdin_pipe[READ_PIPE]);
|
||||
close(stdout_pipe[WRITE_PIPE]);
|
||||
|
||||
/*
|
||||
* write, to the pipe connected to child's stdin, any input specified
|
||||
* after a % in the crontab entry. while we copy, convert any
|
||||
* additional %'s to newlines. when done, if some characters were
|
||||
* written and the last one wasn't a newline, write a newline.
|
||||
*
|
||||
* Note that if the input data won't fit into one pipe buffer (2K
|
||||
* or 4K on most BSD systems), and the child doesn't read its stdin,
|
||||
* we would block here. thus we must fork again.
|
||||
*/
|
||||
|
||||
if (*input_data && fork() == 0) {
|
||||
FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
|
||||
int need_newline = FALSE;
|
||||
int escaped = FALSE;
|
||||
int ch;
|
||||
|
||||
Debug(DPROC, ("[%ld] child2 sending data to grandchild\n",
|
||||
(long) getpid()));
|
||||
|
||||
/* reset the SIGPIPE back to default so the child will terminate
|
||||
* if it tries to write to a closed pipe
|
||||
*/
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
/* close the pipe we don't use, since we inherited it and
|
||||
* are part of its reference count now.
|
||||
*/
|
||||
close(stdout_pipe[READ_PIPE]);
|
||||
|
||||
if (cron_change_user_permanently(e->pwd, env_get("HOME", jobenv)) < 0)
|
||||
_exit(ERROR_EXIT);
|
||||
/* translation:
|
||||
* \% -> %
|
||||
* % -> \n
|
||||
* \x -> \x for all x != %
|
||||
*/
|
||||
while ((ch = *input_data++) != '\0') {
|
||||
if (escaped) {
|
||||
if (ch != '%')
|
||||
putc('\\', out);
|
||||
}
|
||||
else {
|
||||
if (ch == '%')
|
||||
ch = '\n';
|
||||
}
|
||||
|
||||
if (!(escaped = (ch == '\\'))) {
|
||||
putc(ch, out);
|
||||
need_newline = (ch != '\n');
|
||||
}
|
||||
}
|
||||
if (escaped)
|
||||
putc('\\', out);
|
||||
if (need_newline)
|
||||
putc('\n', out);
|
||||
|
||||
/* close the pipe, causing an EOF condition. fclose causes
|
||||
* stdin_pipe[WRITE_PIPE] to be closed, too.
|
||||
*/
|
||||
fclose(out);
|
||||
|
||||
Debug(DPROC, ("[%ld] child2 done sending to grandchild\n",
|
||||
(long) getpid()));
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* close the pipe to the grandkiddie's stdin, since its wicked uncle
|
||||
* ernie back there has it open and will close it when he's done.
|
||||
*/
|
||||
close(stdin_pipe[WRITE_PIPE]);
|
||||
|
||||
children++;
|
||||
|
||||
/*
|
||||
* read output from the grandchild. it's stderr has been redirected to
|
||||
* it's stdout, which has been redirected to our pipe. if there is any
|
||||
* output, we'll be mailing it to the user whose crontab this is...
|
||||
* when the grandchild exits, we'll get EOF.
|
||||
*/
|
||||
|
||||
Debug(DPROC, ("[%ld] child reading output from grandchild\n",
|
||||
(long) getpid()));
|
||||
|
||||
/*local */ {
|
||||
FILE *in = fdopen(stdout_pipe[READ_PIPE], "r");
|
||||
int ch = getc(in);
|
||||
|
||||
if (ch != EOF) {
|
||||
FILE *mail = NULL;
|
||||
int bytes = 1;
|
||||
int status = 0;
|
||||
#if defined(SYSLOG)
|
||||
char logbuf[1024];
|
||||
int bufidx = 0;
|
||||
if (SyslogOutput) {
|
||||
if (ch != '\n')
|
||||
logbuf[bufidx++] = (char)ch;
|
||||
}
|
||||
#endif
|
||||
|
||||
Debug(DPROC | DEXT,
|
||||
("[%ld] got data (%x:%c) from grandchild\n",
|
||||
(long) getpid(), ch, ch));
|
||||
|
||||
/* get name of recipient. this is MAILTO if set to a
|
||||
* valid local username; USER otherwise.
|
||||
*/
|
||||
if (mailto) {
|
||||
/* MAILTO was present in the environment
|
||||
*/
|
||||
if (!*mailto) {
|
||||
/* ... but it's empty. set to NULL
|
||||
*/
|
||||
mailto = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* MAILTO not present, set to USER.
|
||||
*/
|
||||
mailto = usernm;
|
||||
}
|
||||
|
||||
/* get sender address. this is MAILFROM if set (and safe),
|
||||
* the user account name otherwise.
|
||||
*/
|
||||
if (!mailfrom || !*mailfrom || !safe_p(usernm, mailfrom)) {
|
||||
mailfrom = e->pwd->pw_name;
|
||||
}
|
||||
|
||||
/* if we are supposed to be mailing, MAILTO will
|
||||
* be non-NULL. only in this case should we set
|
||||
* up the mail command and subjects and stuff...
|
||||
*/
|
||||
|
||||
/* Also skip it if MailCmd is set to "off" */
|
||||
if (mailto && safe_p(usernm, mailto)
|
||||
&& strncmp(MailCmd,"off",3) && !SyslogOutput) {
|
||||
char **env;
|
||||
char mailcmd[MAX_COMMAND+1]; /* +1 for terminator */
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
char *content_type = env_get("CONTENT_TYPE", jobenv),
|
||||
*content_transfer_encoding =
|
||||
env_get("CONTENT_TRANSFER_ENCODING", jobenv);
|
||||
|
||||
gethostname(hostname, MAXHOSTNAMELEN);
|
||||
|
||||
if (MailCmd[0] == '\0') {
|
||||
int len;
|
||||
|
||||
len = snprintf(mailcmd, sizeof mailcmd, MAILFMT, MAILARG, mailfrom);
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "mailcmd snprintf failed\n");
|
||||
(void) _exit(ERROR_EXIT);
|
||||
}
|
||||
if (sizeof mailcmd <= (size_t) len) {
|
||||
fprintf(stderr, "mailcmd too long\n");
|
||||
(void) _exit(ERROR_EXIT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
strncpy(mailcmd, MailCmd, MAX_COMMAND+1);
|
||||
}
|
||||
if (!(mail = cron_popen(mailcmd, "w", e->pwd, jobenv))) {
|
||||
perror(mailcmd);
|
||||
(void) _exit(ERROR_EXIT);
|
||||
}
|
||||
|
||||
fprintf(mail, "From: \"(Cron Daemon)\" <%s>\n", mailfrom);
|
||||
fprintf(mail, "To: %s\n", mailto);
|
||||
fprintf(mail, "Subject: Cron <%s@%s> %s\n",
|
||||
usernm, first_word(hostname, "."), e->cmd);
|
||||
|
||||
#ifdef MAIL_DATE
|
||||
fprintf(mail, "Date: %s\n", arpadate(&StartTime));
|
||||
#endif /*MAIL_DATE */
|
||||
fprintf(mail, "MIME-Version: 1.0\n");
|
||||
if (content_type == NULL) {
|
||||
fprintf(mail, "Content-Type: text/plain; charset=%s\n",
|
||||
cron_default_mail_charset);
|
||||
}
|
||||
else { /* user specified Content-Type header.
|
||||
* disallow new-lines for security reasons
|
||||
* (else users could specify arbitrary mail headers!)
|
||||
*/
|
||||
char *nl = content_type;
|
||||
size_t ctlen = strlen(content_type);
|
||||
while ((*nl != '\0')
|
||||
&& ((nl = strchr(nl, '\n')) != NULL)
|
||||
&& (nl < (content_type + ctlen))
|
||||
)
|
||||
*nl = ' ';
|
||||
fprintf(mail, "Content-Type: %s\n", content_type);
|
||||
}
|
||||
if (content_transfer_encoding == NULL) {
|
||||
fprintf(mail, "Content-Transfer-Encoding: 8bit\n");
|
||||
}
|
||||
else {
|
||||
char *nl = content_transfer_encoding;
|
||||
size_t ctlen = strlen(content_transfer_encoding);
|
||||
while ((*nl != '\0')
|
||||
&& ((nl = strchr(nl, '\n')) != NULL)
|
||||
&& (nl < (content_transfer_encoding + ctlen))
|
||||
)
|
||||
*nl = ' ';
|
||||
fprintf(mail, "Content-Transfer-Encoding: %s\n",
|
||||
content_transfer_encoding);
|
||||
}
|
||||
|
||||
/* The Auto-Submitted header is
|
||||
* defined (and suggested by) RFC3834.
|
||||
*/
|
||||
fprintf(mail, "Auto-Submitted: auto-generated\n");
|
||||
fprintf(mail, "Precedence: bulk\n");
|
||||
|
||||
for (env = jobenv; *env; env++)
|
||||
fprintf(mail, "X-Cron-Env: <%s>\n", *env);
|
||||
fprintf(mail, "\n");
|
||||
|
||||
/* this was the first char from the pipe
|
||||
*/
|
||||
putc(ch, mail);
|
||||
}
|
||||
|
||||
/* we have to read the input pipe no matter whether
|
||||
* we mail or not, but obviously we only write to
|
||||
* mail pipe if we ARE mailing.
|
||||
*/
|
||||
|
||||
while (EOF != (ch = getc(in))) {
|
||||
if (ch == '\r')
|
||||
continue;
|
||||
bytes++;
|
||||
if (mail)
|
||||
putc(ch, mail);
|
||||
#if defined(SYSLOG)
|
||||
if (SyslogOutput) {
|
||||
logbuf[bufidx++] = (char)ch;
|
||||
if ((ch == '\n') || (bufidx == sizeof(logbuf)-1)) {
|
||||
if (ch == '\n')
|
||||
logbuf[bufidx-1] = '\0';
|
||||
else
|
||||
logbuf[bufidx] = '\0';
|
||||
log_it(usernm, getpid(), "CMDOUT", logbuf, 0);
|
||||
bufidx = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* only close pipe if we opened it -- i.e., we're
|
||||
* mailing...
|
||||
*/
|
||||
|
||||
if (mail) {
|
||||
Debug(DPROC, ("[%ld] closing pipe to mail\n", (long) getpid()));
|
||||
/* Note: the pclose will probably see
|
||||
* the termination of the grandchild
|
||||
* in addition to the mail process, since
|
||||
* it (the grandchild) is likely to exit
|
||||
* after closing its stdout.
|
||||
*/
|
||||
status = cron_pclose(mail);
|
||||
}
|
||||
#if defined(SYSLOG)
|
||||
if (SyslogOutput) {
|
||||
if (bufidx) {
|
||||
logbuf[bufidx] = '\0';
|
||||
log_it(usernm, getpid(), "CMDOUT", logbuf, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if there was output and we could not mail it,
|
||||
* log the facts so the poor user can figure out
|
||||
* what's going on.
|
||||
*/
|
||||
if (mail && status && !SyslogOutput) {
|
||||
char buf[MAX_TEMPSTR];
|
||||
|
||||
sprintf(buf,
|
||||
"mailed %d byte%s of output but got status 0x%04x\n",
|
||||
bytes, (bytes == 1) ? "" : "s", status);
|
||||
log_it(usernm, getpid(), "MAIL", buf, 0);
|
||||
}
|
||||
|
||||
} /*if data from grandchild */
|
||||
|
||||
Debug(DPROC, ("[%ld] got EOF from grandchild\n", (long) getpid()));
|
||||
|
||||
fclose(in); /* also closes stdout_pipe[READ_PIPE] */
|
||||
}
|
||||
|
||||
/* wait for children to die.
|
||||
*/
|
||||
for (; children > 0; children--) {
|
||||
WAIT_T waiter;
|
||||
PID_T child;
|
||||
|
||||
Debug(DPROC, ("[%ld] waiting for grandchild #%d to finish\n",
|
||||
(long) getpid(), children));
|
||||
while ((child = wait(&waiter)) < OK && errno == EINTR) ;
|
||||
if (child < OK) {
|
||||
Debug(DPROC,
|
||||
("[%ld] no more grandchildren--mail written?\n",
|
||||
(long) getpid()));
|
||||
break;
|
||||
}
|
||||
Debug(DPROC, ("[%ld] grandchild #%ld finished, status=%04x",
|
||||
(long) getpid(), (long) child, WEXITSTATUS(waiter)));
|
||||
if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
|
||||
Debug(DPROC, (", dumped core"));
|
||||
Debug(DPROC, ("\n"));
|
||||
}
|
||||
if ((e->flags & DONT_LOG) == 0) {
|
||||
char *x = mkprints((u_char *) e->cmd, strlen(e->cmd));
|
||||
|
||||
log_it(usernm, getpid(), "CMDEND", x ? x : "**Unknown command**" , 0);
|
||||
free(x);
|
||||
}
|
||||
return OK_EXIT;
|
||||
}
|
||||
|
||||
static int safe_p(const char *usernm, const char *s) {
|
||||
static const char safe_delim[] = "@!:%-.,_+"; /* conservative! */
|
||||
const char *t;
|
||||
int ch, first;
|
||||
|
||||
for (t = s, first = 1; (ch = *t++) != '\0'; first = 0) {
|
||||
if (isascii(ch) && isprint(ch) &&
|
||||
(isalnum(ch) || (!first && strchr(safe_delim, ch))))
|
||||
continue;
|
||||
log_it(usernm, getpid(), "UNSAFE", s, 0);
|
||||
return (FALSE);
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
711
src/entry.c
Normal file
711
src/entry.c
Normal file
@ -0,0 +1,711 @@
|
||||
/*
|
||||
* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* vix 26jan87 [RCS'd; rest of log is in RCS file]
|
||||
* vix 01jan87 [added line-level error recovery]
|
||||
* vix 31dec86 [added /step to the from-to range, per bob@acornrc]
|
||||
* vix 30dec86 [written]
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bitstring.h"
|
||||
#include "funcs.h"
|
||||
#include "globals.h"
|
||||
#include "macros.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
typedef enum ecode {
|
||||
e_none, e_minute, e_hour, e_dom, e_month, e_dow,
|
||||
e_cmd, e_timespec, e_username, e_option, e_memory
|
||||
} ecode_e;
|
||||
|
||||
static const char *ecodes[] = {
|
||||
"no error",
|
||||
"bad minute",
|
||||
"bad hour",
|
||||
"bad day-of-month",
|
||||
"bad month",
|
||||
"bad day-of-week",
|
||||
"bad command",
|
||||
"bad time specifier",
|
||||
"bad username",
|
||||
"bad option",
|
||||
"out of memory"
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
R_START,
|
||||
R_AST,
|
||||
R_STEP,
|
||||
R_TERMS,
|
||||
R_NUM1,
|
||||
R_RANGE,
|
||||
R_RANGE_NUM2,
|
||||
R_RANDOM,
|
||||
R_RANDOM_NUM2,
|
||||
R_FINISH,
|
||||
} range_state_t;
|
||||
|
||||
static int get_list(bitstr_t *, int, int, const char *[], int, FILE *),
|
||||
get_range(bitstr_t *, int, int, const char *[], FILE *),
|
||||
get_number(int *, int, const char *[], FILE *),
|
||||
set_element(bitstr_t *, int, int, int);
|
||||
|
||||
void free_entry(entry * e) {
|
||||
free(e->cmd);
|
||||
free(e->pwd);
|
||||
env_free(e->envp);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/* return NULL if eof or syntax error occurs;
|
||||
* otherwise return a pointer to a new entry.
|
||||
*/
|
||||
entry *load_entry(FILE * file, void (*error_func) (), struct passwd *pw,
|
||||
char **envp) {
|
||||
/* this function reads one crontab entry -- the next -- from a file.
|
||||
* it skips any leading blank lines, ignores comments, and returns
|
||||
* NULL if for any reason the entry can't be read and parsed.
|
||||
*
|
||||
* the entry is also parsed here.
|
||||
*
|
||||
* syntax:
|
||||
* user crontab:
|
||||
* minutes hours doms months dows cmd\n
|
||||
* system crontab (/etc/crontab):
|
||||
* minutes hours doms months dows USERNAME cmd\n
|
||||
*/
|
||||
|
||||
ecode_e ecode = e_none;
|
||||
entry *e = NULL;
|
||||
int ch;
|
||||
char cmd[MAX_COMMAND];
|
||||
char envstr[MAX_ENVSTR];
|
||||
char **tenvp;
|
||||
char *p;
|
||||
struct passwd temppw;
|
||||
int i;
|
||||
|
||||
Debug(DPARS, ("load_entry()...about to eat comments\n"));
|
||||
|
||||
ch = get_char(file);
|
||||
if (ch == EOF)
|
||||
return (NULL);
|
||||
|
||||
/* ch is now the first useful character of a useful line.
|
||||
* it may be an @special or it may be the first character
|
||||
* of a list of minutes.
|
||||
*/
|
||||
|
||||
e = (entry *) calloc(sizeof (entry), sizeof (char));
|
||||
if (e == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* check for '-' as a first character, this option will disable
|
||||
* writing a syslog message about command getting executed
|
||||
*/
|
||||
if (ch == '-') {
|
||||
/* if we are editing system crontab or user uid is 0 (root)
|
||||
* we are allowed to disable logging
|
||||
*/
|
||||
if (pw == NULL || pw->pw_uid == 0)
|
||||
e->flags |= DONT_LOG;
|
||||
else {
|
||||
log_it("CRON", getpid(), "ERROR", "Only privileged user can disable logging", 0);
|
||||
ecode = e_option;
|
||||
goto eof;
|
||||
}
|
||||
ch = get_char(file);
|
||||
if (ch == EOF) {
|
||||
free(e);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == '@') {
|
||||
/* all of these should be flagged and load-limited; i.e.,
|
||||
* instead of @hourly meaning "0 * * * *" it should mean
|
||||
* "close to the front of every hour but not 'til the
|
||||
* system load is low". Problems are: how do you know
|
||||
* what "low" means? (save me from /etc/cron.conf!) and:
|
||||
* how to guarantee low variance (how low is low?), which
|
||||
* means how to we run roughly every hour -- seems like
|
||||
* we need to keep a history or let the first hour set
|
||||
* the schedule, which means we aren't load-limited
|
||||
* anymore. too much for my overloaded brain. (vix, jan90)
|
||||
* HINT
|
||||
*/
|
||||
ch = get_string(cmd, MAX_COMMAND, file, " \t\n");
|
||||
if (!strcmp("reboot", cmd)) {
|
||||
e->flags |= WHEN_REBOOT;
|
||||
}
|
||||
else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)) {
|
||||
bit_set(e->minute, 0);
|
||||
bit_set(e->hour, 0);
|
||||
bit_set(e->dom, 0);
|
||||
bit_set(e->month, 0);
|
||||
bit_nset(e->dow, 0, LAST_DOW - FIRST_DOW);
|
||||
e->flags |= DOW_STAR;
|
||||
}
|
||||
else if (!strcmp("monthly", cmd)) {
|
||||
bit_set(e->minute, 0);
|
||||
bit_set(e->hour, 0);
|
||||
bit_set(e->dom, 0);
|
||||
bit_nset(e->month, 0, LAST_MONTH - FIRST_MONTH);
|
||||
bit_nset(e->dow, 0, LAST_DOW - FIRST_DOW);
|
||||
e->flags |= DOW_STAR;
|
||||
}
|
||||
else if (!strcmp("weekly", cmd)) {
|
||||
bit_set(e->minute, 0);
|
||||
bit_set(e->hour, 0);
|
||||
bit_nset(e->dom, 0, LAST_DOM - FIRST_DOM);
|
||||
bit_nset(e->month, 0, LAST_MONTH - FIRST_MONTH);
|
||||
bit_set(e->dow, 0);
|
||||
e->flags |= DOM_STAR;
|
||||
}
|
||||
else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
|
||||
bit_set(e->minute, 0);
|
||||
bit_set(e->hour, 0);
|
||||
bit_nset(e->dom, 0, LAST_DOM - FIRST_DOM);
|
||||
bit_nset(e->month, 0, LAST_MONTH - FIRST_MONTH);
|
||||
bit_nset(e->dow, 0, LAST_DOW - FIRST_DOW);
|
||||
}
|
||||
else if (!strcmp("hourly", cmd)) {
|
||||
bit_set(e->minute, 0);
|
||||
bit_nset(e->hour, 0, LAST_HOUR - FIRST_HOUR);
|
||||
bit_nset(e->dom, 0, LAST_DOM - FIRST_DOM);
|
||||
bit_nset(e->month, 0, LAST_MONTH - FIRST_MONTH);
|
||||
bit_nset(e->dow, 0, LAST_DOW - FIRST_DOW);
|
||||
e->flags |= HR_STAR;
|
||||
}
|
||||
else {
|
||||
ecode = e_timespec;
|
||||
goto eof;
|
||||
}
|
||||
/* Advance past whitespace between shortcut and
|
||||
* username/command.
|
||||
*/
|
||||
Skip_Blanks(ch, file);
|
||||
if (ch == EOF || ch == '\n') {
|
||||
ecode = e_cmd;
|
||||
goto eof;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug(DPARS, ("load_entry()...about to parse numerics\n"));
|
||||
|
||||
if (ch == '*')
|
||||
e->flags |= MIN_STAR;
|
||||
ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE, PPC_NULL, ch, file);
|
||||
if (ch == EOF) {
|
||||
ecode = e_minute;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* hours
|
||||
*/
|
||||
|
||||
if (ch == '*')
|
||||
e->flags |= HR_STAR;
|
||||
ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR, PPC_NULL, ch, file);
|
||||
if (ch == EOF) {
|
||||
ecode = e_hour;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* DOM (days of month)
|
||||
*/
|
||||
|
||||
if (ch == '*')
|
||||
e->flags |= DOM_STAR;
|
||||
ch = get_list(e->dom, FIRST_DOM, LAST_DOM, PPC_NULL, ch, file);
|
||||
if (ch == EOF) {
|
||||
ecode = e_dom;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* month
|
||||
*/
|
||||
|
||||
ch = get_list(e->month, FIRST_MONTH, LAST_MONTH, MonthNames, ch, file);
|
||||
if (ch == EOF) {
|
||||
ecode = e_month;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* DOW (days of week)
|
||||
*/
|
||||
|
||||
if (ch == '*')
|
||||
e->flags |= DOW_STAR;
|
||||
ch = get_list(e->dow, FIRST_DOW, LAST_DOW, DowNames, ch, file);
|
||||
if (ch == EOF) {
|
||||
ecode = e_dow;
|
||||
goto eof;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sundays equivalent */
|
||||
if (bit_test(e->dow, 0) || bit_test(e->dow, 7)) {
|
||||
bit_set(e->dow, 0);
|
||||
bit_set(e->dow, 7);
|
||||
}
|
||||
|
||||
/* check for permature EOL and catch a common typo */
|
||||
if (ch == '\n' || ch == '*') {
|
||||
ecode = e_cmd;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* ch is the first character of a command, or a username */
|
||||
unget_char(ch, file);
|
||||
|
||||
if (!pw) {
|
||||
char *username = cmd; /* temp buffer */
|
||||
|
||||
Debug(DPARS, ("load_entry()...about to parse username\n"));
|
||||
ch = get_string(username, MAX_COMMAND, file, " \t\n");
|
||||
|
||||
Debug(DPARS, ("load_entry()...got %s\n", username));
|
||||
if (ch == EOF || ch == '\n' || ch == '*') {
|
||||
ecode = e_cmd;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
pw = getpwnam(username);
|
||||
if (pw == NULL) {
|
||||
Debug(DPARS, ("load_entry()...unknown user entry\n"));
|
||||
memset(&temppw, 0, sizeof (temppw));
|
||||
temppw.pw_name = username;
|
||||
temppw.pw_passwd = "";
|
||||
pw = &temppw;
|
||||
} else {
|
||||
Debug(DPARS, ("load_entry()...uid %ld, gid %ld\n",
|
||||
(long) pw->pw_uid, (long) pw->pw_gid));
|
||||
}
|
||||
/* Advance past whitespace before command. */
|
||||
Skip_Blanks(ch, file);
|
||||
|
||||
/* check for permature EOL or EOF */
|
||||
if (ch == EOF || ch == '\n') {
|
||||
ecode = e_cmd;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* ch is the first character of a command */
|
||||
unget_char(ch, file);
|
||||
}
|
||||
|
||||
if ((e->pwd = pw_dup(pw)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
memset(e->pwd->pw_passwd, 0, strlen(e->pwd->pw_passwd));
|
||||
|
||||
p = env_get("RANDOM_DELAY", envp);
|
||||
if (p) {
|
||||
char *endptr;
|
||||
long val;
|
||||
|
||||
errno = 0; /* To distinguish success/failure after call */
|
||||
val = strtol(p, &endptr, 10);
|
||||
if (errno != 0 || val < 0 || val > 24*60) {
|
||||
log_it("CRON", getpid(), "ERROR", "bad value of RANDOM_DELAY", 0);
|
||||
} else {
|
||||
e->delay = (int)((double)val * RandomScale);
|
||||
}
|
||||
}
|
||||
|
||||
/* copy and fix up environment. some variables are just defaults and
|
||||
* others are overrides.
|
||||
*/
|
||||
if ((e->envp = env_copy(envp)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
if (!env_get("SHELL", e->envp)) {
|
||||
if (glue_strings(envstr, sizeof envstr, "SHELL", _PATH_BSHELL, '=')) {
|
||||
if ((tenvp = env_set(e->envp, envstr)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
e->envp = tenvp;
|
||||
}
|
||||
else
|
||||
log_it("CRON", getpid(), "ERROR", "can't set SHELL", 0);
|
||||
}
|
||||
if ((tenvp = env_update_home(e->envp, pw->pw_dir)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
e->envp = tenvp;
|
||||
#ifndef LOGIN_CAP
|
||||
/* If login.conf is in used we will get the default PATH later. */
|
||||
if (!env_get("PATH", e->envp)) {
|
||||
char *defpath;
|
||||
|
||||
if (ChangePath)
|
||||
defpath = _PATH_DEFPATH;
|
||||
else {
|
||||
defpath = getenv("PATH");
|
||||
if (defpath == NULL)
|
||||
defpath = _PATH_DEFPATH;
|
||||
}
|
||||
|
||||
if (glue_strings(envstr, sizeof envstr, "PATH", defpath, '=')) {
|
||||
if ((tenvp = env_set(e->envp, envstr)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
e->envp = tenvp;
|
||||
}
|
||||
else
|
||||
log_it("CRON", getpid(), "ERROR", "can't set PATH", 0);
|
||||
}
|
||||
#endif /* LOGIN_CAP */
|
||||
if (glue_strings(envstr, sizeof envstr, "LOGNAME", pw->pw_name, '=')) {
|
||||
if ((tenvp = env_set(e->envp, envstr)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
e->envp = tenvp;
|
||||
}
|
||||
else
|
||||
log_it("CRON", getpid(), "ERROR", "can't set LOGNAME", 0);
|
||||
#if defined(BSD) || defined(__linux)
|
||||
if (glue_strings(envstr, sizeof envstr, "USER", pw->pw_name, '=')) {
|
||||
if ((tenvp = env_set(e->envp, envstr)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
e->envp = tenvp;
|
||||
}
|
||||
else
|
||||
log_it("CRON", getpid(), "ERROR", "can't set USER", 0);
|
||||
#endif
|
||||
|
||||
Debug(DPARS, ("load_entry()...about to parse command\n"));
|
||||
|
||||
/* Everything up to the next \n or EOF is part of the command...
|
||||
* too bad we don't know in advance how long it will be, since we
|
||||
* need to malloc a string for it... so, we limit it to MAX_COMMAND.
|
||||
*/
|
||||
ch = get_string(cmd, MAX_COMMAND, file, "\n");
|
||||
|
||||
/* a file without a \n before the EOF is rude, so we'll complain...
|
||||
*/
|
||||
if (ch == EOF) {
|
||||
ecode = e_cmd;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
/* got the command in the 'cmd' string; save it in *e.
|
||||
*/
|
||||
if ((e->cmd = strdup(cmd)) == NULL) {
|
||||
ecode = e_memory;
|
||||
goto eof;
|
||||
}
|
||||
|
||||
Debug(DPARS, ("load_entry()...returning successfully\n"));
|
||||
|
||||
/* success, fini, return pointer to the entry we just created...
|
||||
*/
|
||||
return (e);
|
||||
|
||||
eof:
|
||||
if (e) {
|
||||
if (e->envp)
|
||||
env_free(e->envp);
|
||||
free(e->pwd);
|
||||
free(e->cmd);
|
||||
free(e);
|
||||
}
|
||||
for (i = 0; i < MAX_COMMAND && ch != '\n' && !feof(file); i++)
|
||||
ch = get_char(file);
|
||||
if (ecode != e_none && error_func)
|
||||
(*error_func) (ecodes[(int) ecode]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
get_list(bitstr_t * bits, int low, int high, const char *names[],
|
||||
int ch, FILE * file) {
|
||||
int done;
|
||||
|
||||
/* we know that we point to a non-blank character here;
|
||||
* must do a Skip_Blanks before we exit, so that the
|
||||
* next call (or the code that picks up the cmd) can
|
||||
* assume the same thing.
|
||||
*/
|
||||
|
||||
Debug(DPARS | DEXT, ("get_list()...entered\n"));
|
||||
|
||||
/* list = range {"," range}
|
||||
*/
|
||||
/* clear the bit string, since the default is 'off'.
|
||||
*/
|
||||
bit_nclear(bits, 0, (high - low));
|
||||
|
||||
/* process all ranges
|
||||
*/
|
||||
done = FALSE;
|
||||
/* unget ch to allow get_range() to process it properly
|
||||
*/
|
||||
unget_char(ch, file);
|
||||
while (!done) {
|
||||
if (EOF == (ch = get_range(bits, low, high, names, file)))
|
||||
return (EOF);
|
||||
if (ch == ',')
|
||||
continue;
|
||||
else
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
/* exiting. skip to some blanks, then skip over the blanks.
|
||||
*/
|
||||
Skip_Nonblanks(ch, file)
|
||||
Skip_Blanks(ch, file)
|
||||
|
||||
Debug(DPARS | DEXT, ("get_list()...exiting w/ %02x\n", ch));
|
||||
|
||||
return (ch);
|
||||
}
|
||||
|
||||
inline static int is_separator(int ch) {
|
||||
switch (ch) {
|
||||
case '\t':
|
||||
case '\n':
|
||||
case ' ':
|
||||
case ',':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
get_range(bitstr_t * bits, int low, int high, const char *names[],
|
||||
FILE * file) {
|
||||
/* range = number | number "-" number [ "/" number ]
|
||||
* | [number] "~" [number]
|
||||
*/
|
||||
|
||||
int ch, i, num1, num2, num3;
|
||||
|
||||
/* default value for step
|
||||
*/
|
||||
num3 = 1;
|
||||
range_state_t state = R_START;
|
||||
|
||||
while (state != R_FINISH && ((ch = get_char(file)) != EOF)) {
|
||||
switch (state) {
|
||||
case R_START:
|
||||
if (ch == '*') {
|
||||
num1 = low;
|
||||
num2 = high;
|
||||
state = R_AST;
|
||||
break;
|
||||
}
|
||||
if (ch == '~') {
|
||||
num1 = low;
|
||||
state = R_RANDOM;
|
||||
break;
|
||||
}
|
||||
unget_char(ch, file);
|
||||
if (get_number(&num1, low, names, file) != EOF) {
|
||||
state = R_NUM1;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_AST:
|
||||
if (ch == '/') {
|
||||
state = R_STEP;
|
||||
break;
|
||||
}
|
||||
if (is_separator(ch)) {
|
||||
state = R_FINISH;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_STEP:
|
||||
unget_char(ch, file);
|
||||
if (get_number(&num3, 0, PPC_NULL, file) != EOF
|
||||
&& num3 != 0) {
|
||||
state = R_TERMS;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_TERMS:
|
||||
if (is_separator(ch)) {
|
||||
state = R_FINISH;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_NUM1:
|
||||
if (ch == '-') {
|
||||
state = R_RANGE;
|
||||
break;
|
||||
}
|
||||
if (ch == '~') {
|
||||
state = R_RANDOM;
|
||||
break;
|
||||
}
|
||||
if (is_separator(ch)) {
|
||||
num2 = num1;
|
||||
state = R_FINISH;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_RANGE:
|
||||
unget_char(ch, file);
|
||||
if (get_number(&num2, low, names, file) != EOF) {
|
||||
state = R_RANGE_NUM2;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_RANGE_NUM2:
|
||||
if (ch == '/') {
|
||||
state = R_STEP;
|
||||
break;
|
||||
}
|
||||
if (is_separator(ch)) {
|
||||
state = R_FINISH;
|
||||
break;
|
||||
}
|
||||
return (EOF);
|
||||
|
||||
case R_RANDOM:
|
||||
if (is_separator(ch)) {
|
||||
num2 = high;
|
||||
state = R_FINISH;
|
||||
}
|
||||
else if (unget_char(ch, file),
|
||||
get_number(&num2, low, names, file) != EOF) {
|
||||
state = R_TERMS;
|
||||
}
|
||||
/* fail if couldn't find match on previous term
|
||||
*/
|
||||
else
|
||||
return (EOF);
|
||||
|
||||
/* if invalid random range was selected */
|
||||
if (num1 > num2)
|
||||
return (EOF);
|
||||
|
||||
/* select random number in range <num1, num2>
|
||||
*/
|
||||
num1 = num2 = random() % (num2 - num1 + 1) + num1;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* We should never get here
|
||||
*/
|
||||
return (EOF);
|
||||
}
|
||||
}
|
||||
if (state != R_FINISH || ch == EOF)
|
||||
return (EOF);
|
||||
|
||||
for (i = num1; i <= num2; i += num3)
|
||||
if (EOF == set_element(bits, low, high, i)) {
|
||||
unget_char(ch, file);
|
||||
return (EOF);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int
|
||||
get_number(int *numptr, int low, const char *names[], FILE * file) {
|
||||
char temp[MAX_TEMPSTR], *pc;
|
||||
int len, i, ch;
|
||||
char *endptr;
|
||||
|
||||
pc = temp;
|
||||
len = 0;
|
||||
|
||||
/* get all alnum characters available */
|
||||
while (isalnum((ch = get_char(file)))) {
|
||||
if (++len >= MAX_TEMPSTR)
|
||||
goto bad;
|
||||
*pc++ = (char)ch;
|
||||
}
|
||||
*pc = '\0';
|
||||
if (len == 0)
|
||||
goto bad;
|
||||
|
||||
unget_char(ch, file);
|
||||
|
||||
/* try to get number */
|
||||
*numptr = (int) strtol(temp, &endptr, 10);
|
||||
if (*endptr == '\0' && temp != endptr) {
|
||||
/* We have a number */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no numbers, look for a string if we have any */
|
||||
if (names) {
|
||||
for (i = 0; names[i] != NULL; i++) {
|
||||
Debug(DPARS | DEXT, ("get_num, compare(%s,%s)\n", names[i], temp));
|
||||
if (strcasecmp(names[i], temp) == 0) {
|
||||
*numptr = i + low;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
bad:
|
||||
unget_char(ch, file);
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
static int set_element(bitstr_t * bits, int low, int high, int number) {
|
||||
Debug(DPARS | DEXT, ("set_element(?,%d,%d,%d)\n", low, high, number));
|
||||
|
||||
if (number < low || number > high)
|
||||
return (EOF);
|
||||
|
||||
bit_set(bits, (number - low));
|
||||
return (OK);
|
||||
}
|
305
src/env.c
Normal file
305
src/env.c
Normal file
@ -0,0 +1,305 @@
|
||||
/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "funcs.h"
|
||||
|
||||
#if defined(BSD)
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
char **env_init(void) {
|
||||
char **p = (char **) malloc(sizeof (char *));
|
||||
|
||||
if (p != NULL)
|
||||
p[0] = NULL;
|
||||
return (p);
|
||||
}
|
||||
|
||||
void env_free(char **envp) {
|
||||
char **p;
|
||||
|
||||
for (p = envp; *p != NULL; p++)
|
||||
free(*p);
|
||||
free(envp);
|
||||
}
|
||||
|
||||
char **env_copy(char **envp) {
|
||||
int save_errno;
|
||||
size_t count, i;
|
||||
char **p;
|
||||
|
||||
for (count = 0; envp[count] != NULL; count++) ;
|
||||
|
||||
p = (char **) malloc((count + 1) * sizeof (char *)); /* 1 for the NULL */
|
||||
if (p != NULL) {
|
||||
for (i = 0; i < count; i++)
|
||||
if ((p[i] = strdup(envp[i])) == NULL) {
|
||||
save_errno = errno;
|
||||
while (i-- > 0)
|
||||
free(p[i]);
|
||||
free(p);
|
||||
errno = save_errno;
|
||||
return (NULL);
|
||||
}
|
||||
p[count] = NULL;
|
||||
}
|
||||
return (p);
|
||||
}
|
||||
|
||||
char **env_set(char **envp, const char *envstr) {
|
||||
size_t count, found;
|
||||
char **p, *envtmp;
|
||||
|
||||
/*
|
||||
* count the number of elements, including the null pointer;
|
||||
* also set 'found' to -1 or index of entry if already in here.
|
||||
*/
|
||||
found = (size_t)-1;
|
||||
for (count = 0; envp[count] != NULL; count++) {
|
||||
if (!strcmp_until(envp[count], envstr, '='))
|
||||
found = count;
|
||||
}
|
||||
count++; /* for the NULL */
|
||||
|
||||
if (found != (size_t)-1) {
|
||||
/*
|
||||
* it exists already, so just free the existing setting,
|
||||
* save our new one there, and return the existing array.
|
||||
*/
|
||||
if ((envtmp = strdup(envstr)) == NULL)
|
||||
return (NULL);
|
||||
free(envp[found]);
|
||||
envp[found] = envtmp;
|
||||
return (envp);
|
||||
}
|
||||
|
||||
/*
|
||||
* it doesn't exist yet, so resize the array, move null pointer over
|
||||
* one, save our string over the old null pointer, and return resized
|
||||
* array.
|
||||
*/
|
||||
if ((envtmp = strdup(envstr)) == NULL)
|
||||
return (NULL);
|
||||
p = (char **) realloc((void *) envp,
|
||||
(count + 1) * sizeof (char *));
|
||||
if (p == NULL) {
|
||||
free(envtmp);
|
||||
return (NULL);
|
||||
}
|
||||
p[count] = p[count - 1];
|
||||
p[count - 1] = envtmp;
|
||||
return (p);
|
||||
}
|
||||
|
||||
int env_set_from_environ(char ***envpp) {
|
||||
static const char *names[] = {
|
||||
"LANG",
|
||||
"LC_CTYPE",
|
||||
"LC_NUMERIC",
|
||||
"LC_TIME",
|
||||
"LC_COLLATE",
|
||||
"LC_MONETARY",
|
||||
"LC_MESSAGES",
|
||||
"LC_PAPER",
|
||||
"LC_NAME",
|
||||
"LC_ADDRESS",
|
||||
"LC_TELEPHONE",
|
||||
"LC_MEASUREMENT",
|
||||
"LC_IDENTIFICATION",
|
||||
"LC_ALL",
|
||||
"LANGUAGE",
|
||||
"RANDOM_DELAY",
|
||||
NULL
|
||||
};
|
||||
const char **name;
|
||||
char **procenv;
|
||||
|
||||
for (procenv = environ; *procenv != NULL; ++procenv) {
|
||||
for (name = names; *name != NULL; ++name) {
|
||||
size_t namelen;
|
||||
|
||||
namelen = strlen(*name);
|
||||
if (strncmp(*name, *procenv, namelen) == 0
|
||||
&& (*procenv)[namelen] == '=') {
|
||||
char **tmpenv;
|
||||
|
||||
tmpenv = env_set(*envpp, *procenv);
|
||||
if (tmpenv == NULL)
|
||||
return FALSE;
|
||||
*envpp = tmpenv;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* The following states are used by load_env(), traversed in order: */
|
||||
enum env_state {
|
||||
NAMEI, /* First char of NAME, may be quote */
|
||||
NAME, /* Subsequent chars of NAME */
|
||||
EQ1, /* After end of name, looking for '=' sign */
|
||||
EQ2, /* After '=', skipping whitespace */
|
||||
VALUEI, /* First char of VALUE, may be quote */
|
||||
VALUE, /* Subsequent chars of VALUE */
|
||||
FINI, /* All done, skipping trailing whitespace */
|
||||
ERROR, /* Error */
|
||||
};
|
||||
|
||||
/* return ERR = end of file
|
||||
* FALSE = not an env setting (file was repositioned)
|
||||
* TRUE = was an env setting
|
||||
*/
|
||||
int load_env(char *envstr, FILE * f) {
|
||||
long filepos;
|
||||
int fileline;
|
||||
enum env_state state;
|
||||
char quotechar, *c, *str, *val;
|
||||
|
||||
filepos = ftell(f);
|
||||
fileline = LineNumber;
|
||||
if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
|
||||
return (ERR);
|
||||
|
||||
Debug(DPARS, ("load_env, read <%s>\n", envstr));
|
||||
|
||||
val = str = envstr;
|
||||
state = NAMEI;
|
||||
quotechar = '\0';
|
||||
c = envstr;
|
||||
while (state != ERROR && *c) {
|
||||
switch (state) {
|
||||
case NAMEI:
|
||||
case VALUEI:
|
||||
if (*c == '\'' || *c == '"')
|
||||
quotechar = *c++;
|
||||
state++;
|
||||
/* FALLTHROUGH */
|
||||
case NAME:
|
||||
case VALUE:
|
||||
if (quotechar) {
|
||||
if (*c == quotechar) {
|
||||
state++;
|
||||
c++;
|
||||
break;
|
||||
}
|
||||
if (state == NAME && *c == '=') {
|
||||
state = ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (state == NAME) {
|
||||
if (isspace((unsigned char) *c)) {
|
||||
c++;
|
||||
state++;
|
||||
break;
|
||||
}
|
||||
if (*c == '=') {
|
||||
state++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*str++ = *c++;
|
||||
break;
|
||||
|
||||
case EQ1:
|
||||
if (*c == '=') {
|
||||
state++;
|
||||
quotechar = '\0';
|
||||
*str++ = *c;
|
||||
val = str;
|
||||
}
|
||||
else {
|
||||
if (!isspace((unsigned char) *c))
|
||||
state = ERROR;
|
||||
}
|
||||
c++;
|
||||
break;
|
||||
|
||||
case EQ2:
|
||||
case FINI:
|
||||
if (isspace((unsigned char) *c))
|
||||
c++;
|
||||
else
|
||||
state++;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (state != FINI && state != EQ2 && !(state == VALUE && !quotechar)) {
|
||||
Debug(DPARS, ("load_env, not an env var, state = %d\n", state));
|
||||
if (fseek(f, filepos, 0)) {
|
||||
return ERR;
|
||||
}
|
||||
Set_LineNum(fileline);
|
||||
return (FALSE);
|
||||
}
|
||||
*str = '\0';
|
||||
if (state == VALUE) {
|
||||
/* End of unquoted value: trim trailing whitespace */
|
||||
while (str > val && isspace((unsigned char)str[-1]))
|
||||
*(--str) = '\0';
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char *env_get(const char *name, char **envp) {
|
||||
size_t len = strlen(name);
|
||||
char *p, *q;
|
||||
|
||||
while ((p = *envp++) != NULL) {
|
||||
if (!(q = strchr(p, '=')))
|
||||
continue;
|
||||
if ((size_t)(q - p) == len && !strncmp(p, name, len))
|
||||
return (q + 1);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char **env_update_home(char **envp, const char *dir) {
|
||||
char envstr[MAX_ENVSTR];
|
||||
|
||||
if (dir == NULL || *dir == '\0' || env_get("HOME", envp)) {
|
||||
return envp;
|
||||
}
|
||||
|
||||
if (glue_strings(envstr, sizeof envstr, "HOME", dir, '=')) {
|
||||
envp = env_set(envp, envstr);
|
||||
}
|
||||
else
|
||||
log_it("CRON", getpid(), "ERROR", "can't set HOME", 0);
|
||||
|
||||
return envp;
|
||||
}
|
91
src/externs.h
Normal file
91
src/externs.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* Copyright 1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* reorder these #include's at your peril */
|
||||
|
||||
#ifndef CRONIE_EXTERNS_H
|
||||
#define CRONIE_EXTERNS_H
|
||||
|
||||
#if defined(LOGIN_CAP)
|
||||
# include <login_cap.h>
|
||||
#endif /*LOGIN_CAP*/
|
||||
|
||||
#if defined(BSD_AUTH)
|
||||
# include <bsd_auth.h>
|
||||
#endif /*BSD_AUTH*/
|
||||
|
||||
#define DIR_T struct dirent
|
||||
#define WAIT_T int
|
||||
#define SIG_T sig_t
|
||||
#define TIME_T time_t
|
||||
#define PID_T pid_t
|
||||
|
||||
#ifndef TZNAME_ALREADY_DEFINED
|
||||
extern char *tzname[2];
|
||||
#endif
|
||||
#define TZONE(tm) tzname[(tm).tm_isdst]
|
||||
|
||||
#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(__sun) || defined(_AIX)
|
||||
# define HAVE_SAVED_UIDS
|
||||
#endif
|
||||
|
||||
#define MY_UID(pw) getuid()
|
||||
#define MY_GID(pw) getgid()
|
||||
|
||||
/* getopt() isn't part of POSIX. some systems define it in <stdlib.h> anyway.
|
||||
* of those that do, some complain that our definition is different and some
|
||||
* do not. to add to the misery and confusion, some systems define getopt()
|
||||
* in ways that we cannot predict or comprehend, yet do not define the adjunct
|
||||
* external variables needed for the interface.
|
||||
*/
|
||||
#if (!defined(BSD) || (BSD < 198911))
|
||||
int getopt(int, char * const *, const char *);
|
||||
#endif
|
||||
|
||||
#if (!defined(BSD) || (BSD < 199103))
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
#endif
|
||||
|
||||
/* digital unix needs this but does not give us a way to identify it.
|
||||
*/
|
||||
extern int flock(int, int);
|
||||
|
||||
/* not all systems who provide flock() provide these definitions.
|
||||
*/
|
||||
#ifndef LOCK_SH
|
||||
# define LOCK_SH 1
|
||||
#endif
|
||||
#ifndef LOCK_EX
|
||||
# define LOCK_EX 2
|
||||
#endif
|
||||
#ifndef LOCK_NB
|
||||
# define LOCK_NB 4
|
||||
#endif
|
||||
#ifndef LOCK_UN
|
||||
# define LOCK_UN 8
|
||||
#endif
|
||||
|
||||
#ifndef WCOREDUMP
|
||||
# define WCOREDUMP(st) (((st) & 0200) != 0)
|
||||
#endif
|
||||
|
||||
#endif /* CRONIE_EXTERNS_H */
|
131
src/funcs.h
Normal file
131
src/funcs.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* $Id: funcs.h,v 1.9 2004/01/23 18:56:42 vixie Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* We should reorg this into sections by module.
|
||||
*/
|
||||
|
||||
#ifndef CRONIE_FUNCS_H
|
||||
#define CRONIE_FUNCS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "externs.h"
|
||||
#include "structs.h"
|
||||
|
||||
void set_cron_uid(void),
|
||||
check_spool_dir(void),
|
||||
open_logfile(void),
|
||||
sigpipe_func(void),
|
||||
job_add(entry *, user *),
|
||||
do_command(entry *, user *),
|
||||
link_user(cron_db *, user *),
|
||||
unlink_user(cron_db *, user *),
|
||||
free_user(user *),
|
||||
env_free(char **),
|
||||
unget_char(int, FILE *),
|
||||
free_entry(entry *),
|
||||
acquire_daemonlock(int),
|
||||
log_it(const char *, PID_T, const char *, const char *, int),
|
||||
log_close(void),
|
||||
check_orphans(cron_db *);
|
||||
#if defined WITH_INOTIFY
|
||||
void set_cron_watched(int ),
|
||||
set_cron_unwatched(int ),
|
||||
check_inotify_database(cron_db *);
|
||||
#endif
|
||||
|
||||
int load_database(cron_db *),
|
||||
job_runqueue(void),
|
||||
set_debug_flags(const char *),
|
||||
get_char(FILE *),
|
||||
get_string(char *, int, FILE *, const char *),
|
||||
swap_uids(void),
|
||||
swap_uids_back(void),
|
||||
load_env(char *, FILE *),
|
||||
env_set_from_environ(char ***envpp),
|
||||
cron_pclose(FILE *),
|
||||
glue_strings(char *, size_t, const char *, const char *, char),
|
||||
strcmp_until(const char *, const char *, char),
|
||||
skip_comments(FILE *),
|
||||
allowed(const char * ,const char * ,const char *);
|
||||
|
||||
size_t strlens(const char *, ...),
|
||||
strdtb(char *);
|
||||
|
||||
char *env_get(const char *, char **),
|
||||
*arpadate(time_t *),
|
||||
*mkprints(unsigned char *, size_t),
|
||||
*first_word(const char *, const char *),
|
||||
**env_init(void),
|
||||
**env_copy(char **),
|
||||
**env_set(char **, const char *),
|
||||
**env_update_home(char **, const char *);
|
||||
|
||||
user *load_user(int, struct passwd *, const char *, const char *, const char *),
|
||||
*find_user(cron_db *, const char *, const char *);
|
||||
|
||||
entry *load_entry(FILE *, void (*)(), struct passwd *, char **);
|
||||
|
||||
FILE *cron_popen(char *, const char *, struct passwd *, char **);
|
||||
|
||||
struct passwd *pw_dup(const struct passwd *);
|
||||
|
||||
#ifndef HAVE_STRUCT_TM_TM_GMTOFF
|
||||
long get_gmtoff(time_t *, struct tm *);
|
||||
#endif
|
||||
|
||||
/* Red Hat security stuff (security.c):
|
||||
*/
|
||||
void cron_restore_default_security_context( void );
|
||||
|
||||
int cron_set_job_security_context( entry *e, user *u, char ***jobenvp );
|
||||
|
||||
int cron_open_security_session( struct passwd *pw );
|
||||
|
||||
void cron_close_security_session( void );
|
||||
|
||||
int cron_change_groups( struct passwd *pw );
|
||||
|
||||
int cron_change_user_permanently( struct passwd *pw, char *homedir );
|
||||
|
||||
int get_security_context(const char *name,
|
||||
int crontab_fd,
|
||||
security_context_t *rcontext,
|
||||
const char *tabname
|
||||
);
|
||||
|
||||
void free_security_context( security_context_t *scontext );
|
||||
|
||||
int crontab_security_access(void);
|
||||
|
||||
/* PAM */
|
||||
#ifdef WITH_PAM
|
||||
int cron_start_pam(struct passwd *pw);
|
||||
void cron_close_pam(void);
|
||||
#endif
|
||||
|
||||
#endif /* CRONIE_FUNCS_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user