Drop hurd specific dependency on libc0.3 (>= 2.3.2.ds1-12). It is
no longer needed according to Michael Bunk. Patch from Michael Biebl.
This commit is contained in:
commit
2fe47a3c9f
339
COPYING
Normal file
339
COPYING
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.
|
26
COPYRIGHT
Normal file
26
COPYRIGHT
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Sysvinit is Copyright (C) 1991-2004 Miquel van Smoorenburg
|
||||||
|
|
||||||
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Send patches to sysvinit@savannah.nognu.org
|
||||||
|
|
||||||
|
The of the start-stop-daemon
|
||||||
|
|
||||||
|
* A rewrite of the original Debian's start-stop-daemon Perl script
|
||||||
|
* in C (faster - it is executed many times during system startup).
|
||||||
|
*
|
||||||
|
* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
|
||||||
|
* public domain.
|
||||||
|
|
7
README
Normal file
7
README
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
contrib Unofficial stuff
|
||||||
|
doc Documentation, mostly obsolete
|
||||||
|
man Manual pages, not obsolete
|
||||||
|
obsolete Really obsolete stuff ;)
|
||||||
|
src Source code
|
||||||
|
|
16
contrib/TODO
Normal file
16
contrib/TODO
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
There are several things on the wishlist. See also the "wishlist" bugs filed
|
||||||
|
against sysvinit in the debian bugs system (http://www.debian.org/Bugs/).
|
||||||
|
|
||||||
|
1. A special target for kbrequest, so that extra CHILDs are
|
||||||
|
created (each one needs its own utmp/wtmp bookkeeping)
|
||||||
|
2. Extend the initreq.h interface?
|
||||||
|
3. Add GNU last long options to last
|
||||||
|
|
||||||
|
4. Write all boot messages to a logfile
|
||||||
|
Problem: TIOCCONS ioctl redirects console output, it doesn't copy it.
|
||||||
|
I think this is not easily possible without kernel support.
|
||||||
|
I do not like the idea of booting with a pseudo tty as console and
|
||||||
|
a redirect process behind it writing to both the real console and a
|
||||||
|
logfile - too fragile.
|
||||||
|
|
29
contrib/alexander.viro
Normal file
29
contrib/alexander.viro
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
I proposed moving some stuff to a seperate file, such as the
|
||||||
|
re-exec routines. Alexander wrote:
|
||||||
|
|
||||||
|
|
||||||
|
According to Alexander Viro <viro@math.psu.edu>:
|
||||||
|
> As for the code separation - I think it's nice. Actually, read_inittab()
|
||||||
|
> with get_part() and newFamily are also pretty separatable. Another good
|
||||||
|
> set is any(), spawn(), startup(), spawn_emerg() and start_if_needed().
|
||||||
|
> BTW, fail_check();process_signals(); is equivalent to process_signal();
|
||||||
|
> fail_check();. I think that swapping them (in main loop) would be a good
|
||||||
|
> idea - then we can move fail_check() into start_if_needed(). And one more
|
||||||
|
> - I'ld propose to move start_if_needed to the beginning of the main loop,
|
||||||
|
> as in
|
||||||
|
> foo();
|
||||||
|
> while(1) { bar();foo();
|
||||||
|
> #if 0
|
||||||
|
> baz();
|
||||||
|
> #endif
|
||||||
|
> }
|
||||||
|
> to
|
||||||
|
> while(1) { foo();bar();
|
||||||
|
> #if 0
|
||||||
|
> baz();
|
||||||
|
> #endif
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
>
|
||||||
|
> What do you think about it?
|
||||||
|
|
45
contrib/start-stop-daemon.README
Normal file
45
contrib/start-stop-daemon.README
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
Start-stop-daemon is the program that is used by the DEBIAN style init
|
||||||
|
scripts to start and stop services. This program is part of the "dpkg"
|
||||||
|
package by Ian Jackson. However there is also a seperate C version (the
|
||||||
|
original is in perl) available written by Marek Michalkiewicz. I'm including
|
||||||
|
it for your convinience.
|
||||||
|
|
||||||
|
Note that the latest debian dpkg packages (4.0.18 and later) contain
|
||||||
|
a much improved update-rc.d. This code is almost a year old.
|
||||||
|
|
||||||
|
The original announcement follows:
|
||||||
|
|
||||||
|
|
||||||
|
From: Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>
|
||||||
|
Message-Id: <199606060324.FAA19493@i17linuxb.ists.pwr.wroc.pl>
|
||||||
|
Subject: Fast start-stop-daemon in C
|
||||||
|
To: debian-devel@lists.debian.org
|
||||||
|
Date: Thu, 6 Jun 1996 05:24:18 +0200 (MET DST)
|
||||||
|
|
||||||
|
Some time ago I wrote a faster C replacement for the start-stop-daemon
|
||||||
|
perl script. I use it for some time now (the most recent changes were
|
||||||
|
just a nicer help screen; the code is quite stable).
|
||||||
|
|
||||||
|
This makes the system boot faster (especially on low end machines),
|
||||||
|
and important system startup scripts no longer depend on another big
|
||||||
|
package (perl). Maybe in the future we can get to the point where
|
||||||
|
a minimal system will work without perl installed at all (packages
|
||||||
|
which need it in {pre,post}{inst,rm} scripts would depend on perl).
|
||||||
|
|
||||||
|
The only problem known so far to me is that I have to reinstall this
|
||||||
|
program after every dpkg upgrade which overwrites it with that nice
|
||||||
|
slooow perl script :-).
|
||||||
|
|
||||||
|
Just compile this program and drop the binary in /usr/sbin instead
|
||||||
|
of the original /usr/sbin/start-stop-daemon perl script (make a copy
|
||||||
|
of it first, just in case). See below for source code. I placed it
|
||||||
|
in the public domain, but if it has to be GPL-ed to be included in
|
||||||
|
dpkg, just tell me. Including it in dpkg would close Bug#1670.
|
||||||
|
|
||||||
|
I am posting it here so that it can be tested by more people than
|
||||||
|
just me. Bugs are unlikely though.
|
||||||
|
|
||||||
|
Have fun,
|
||||||
|
|
||||||
|
Marek
|
||||||
|
|
430
contrib/start-stop-daemon.c
Normal file
430
contrib/start-stop-daemon.c
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
* A rewrite of the original Debian's start-stop-daemon Perl script
|
||||||
|
* in C (faster - it is executed many times during system startup).
|
||||||
|
*
|
||||||
|
* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
|
||||||
|
* public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
#define VERSION "version 0.3, 1996-06-05"
|
||||||
|
|
||||||
|
static int testmode = 0;
|
||||||
|
static int quietmode = 0;
|
||||||
|
static int exitnodo = 1;
|
||||||
|
static int start = 0;
|
||||||
|
static int stop = 0;
|
||||||
|
static int signal_nr = 15;
|
||||||
|
static int user_id = -1;
|
||||||
|
static const char *userspec = NULL;
|
||||||
|
static const char *cmdname = NULL;
|
||||||
|
static char *execname = NULL;
|
||||||
|
static char *startas = NULL;
|
||||||
|
static const char *pidfile = NULL;
|
||||||
|
static const char *progname = "";
|
||||||
|
|
||||||
|
static struct stat exec_stat;
|
||||||
|
|
||||||
|
struct pid_list {
|
||||||
|
struct pid_list *next;
|
||||||
|
int pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pid_list *found = NULL;
|
||||||
|
static struct pid_list *killed = NULL;
|
||||||
|
|
||||||
|
static void *xmalloc(int size);
|
||||||
|
static void push(struct pid_list **list, int pid);
|
||||||
|
static void do_help(void);
|
||||||
|
static void parse_options(int argc, char * const *argv);
|
||||||
|
static int pid_is_exec(int pid, const struct stat *esb);
|
||||||
|
static int pid_is_user(int pid, int uid);
|
||||||
|
static int pid_is_cmd(int pid, const char *name);
|
||||||
|
static void check(int pid);
|
||||||
|
static void do_pidfile(const char *name);
|
||||||
|
static void do_procfs(void);
|
||||||
|
static void do_stop(void);
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
static void fatal(const char *format, ...)
|
||||||
|
__attribute__((noreturn, format(printf, 1, 2)));
|
||||||
|
static void badusage(const char *msg)
|
||||||
|
__attribute__((noreturn));
|
||||||
|
#else
|
||||||
|
static void fatal(const char *format, ...);
|
||||||
|
static void badusage(const char *msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
fatal(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: ", progname);
|
||||||
|
va_start(arglist, format);
|
||||||
|
vfprintf(stderr, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
putc('\n', stderr);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
xmalloc(int size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = malloc(size);
|
||||||
|
if (ptr)
|
||||||
|
return ptr;
|
||||||
|
fatal("malloc(%d) failed", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
push(struct pid_list **list, int pid)
|
||||||
|
{
|
||||||
|
struct pid_list *p;
|
||||||
|
|
||||||
|
p = xmalloc(sizeof(*p));
|
||||||
|
p->next = *list;
|
||||||
|
p->pid = pid;
|
||||||
|
*list = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_help(void)
|
||||||
|
{
|
||||||
|
printf("\
|
||||||
|
start-stop-daemon for Debian Linux - small and fast C version written by\n\
|
||||||
|
Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
|
||||||
|
VERSION "\n\
|
||||||
|
\n\
|
||||||
|
Usage:
|
||||||
|
start-stop-daemon -S|--start options ... -- arguments ...\n\
|
||||||
|
start-stop-daemon -K|--stop options ...\n\
|
||||||
|
start-stop-daemon -H|--help\n\
|
||||||
|
start-stop-daemon -V|--version\n\
|
||||||
|
\n\
|
||||||
|
Options (at least one of --exec|--pidfile|--user is required):
|
||||||
|
-x|--exec <executable> program to start/check if it is running\n\
|
||||||
|
-p|--pidfile <pid-file> pid file to check\n\
|
||||||
|
-u|--user <username>|<uid> stop this user's processes\n\
|
||||||
|
-n|--name <process-name> stop processes with this name\n\
|
||||||
|
-s|--signal <signal> signal to send (default 15)\n\
|
||||||
|
-a|--startas <pathname> program to start (default <executable>)\n\
|
||||||
|
-t|--test test mode, don't do anything\n\
|
||||||
|
-o|--oknodo exit status 0 (not 1) if nothing done\n\
|
||||||
|
-q|--quiet | -v, --verbose\n\
|
||||||
|
\n\
|
||||||
|
Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo) 2 = trouble\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
badusage(const char *msg)
|
||||||
|
{
|
||||||
|
if (msg && *msg)
|
||||||
|
fprintf(stderr, "%s: %s\n", progname, msg);
|
||||||
|
fprintf(stderr, "Try `%s --help' for more information.\n", progname);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_options(int argc, char * const *argv)
|
||||||
|
{
|
||||||
|
static struct option longopts[] = {
|
||||||
|
{ "help", 0, NULL, 'H'},
|
||||||
|
{ "stop", 0, NULL, 'K'},
|
||||||
|
{ "start", 0, NULL, 'S'},
|
||||||
|
{ "version", 0, NULL, 'V'},
|
||||||
|
{ "startas", 1, NULL, 'a'},
|
||||||
|
{ "name", 1, NULL, 'n'},
|
||||||
|
{ "oknodo", 0, NULL, 'o'},
|
||||||
|
{ "pidfile", 1, NULL, 'p'},
|
||||||
|
{ "quiet", 0, NULL, 'q'},
|
||||||
|
{ "signal", 1, NULL, 's'},
|
||||||
|
{ "test", 0, NULL, 't'},
|
||||||
|
{ "user", 1, NULL, 'u'},
|
||||||
|
{ "verbose", 0, NULL, 'v'},
|
||||||
|
{ "exec", 1, NULL, 'x'},
|
||||||
|
{ NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:",
|
||||||
|
longopts, (int *) 0);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
case 'H': /* --help */
|
||||||
|
do_help();
|
||||||
|
exit(0);
|
||||||
|
case 'K': /* --stop */
|
||||||
|
stop = 1;
|
||||||
|
break;
|
||||||
|
case 'S': /* --start */
|
||||||
|
start = 1;
|
||||||
|
break;
|
||||||
|
case 'V': /* --version */
|
||||||
|
printf("start-stop-daemon " VERSION "\n");
|
||||||
|
exit(0);
|
||||||
|
case 'a': /* --startas <pathname> */
|
||||||
|
startas = optarg;
|
||||||
|
break;
|
||||||
|
case 'n': /* --name <process-name> */
|
||||||
|
cmdname = optarg;
|
||||||
|
break;
|
||||||
|
case 'o': /* --oknodo */
|
||||||
|
exitnodo = 0;
|
||||||
|
break;
|
||||||
|
case 'p': /* --pidfile <pid-file> */
|
||||||
|
pidfile = optarg;
|
||||||
|
break;
|
||||||
|
case 'q': /* --quiet */
|
||||||
|
quietmode = 1;
|
||||||
|
break;
|
||||||
|
case 's': /* --signal <signal> */
|
||||||
|
if (sscanf(optarg, "%d", &signal_nr) != 1)
|
||||||
|
badusage("--signal takes a numeric argument");
|
||||||
|
break;
|
||||||
|
case 't': /* --test */
|
||||||
|
testmode = 1;
|
||||||
|
break;
|
||||||
|
case 'u': /* --user <username>|<uid> */
|
||||||
|
userspec = optarg;
|
||||||
|
break;
|
||||||
|
case 'v': /* --verbose */
|
||||||
|
quietmode = -1;
|
||||||
|
break;
|
||||||
|
case 'x': /* --exec <executable> */
|
||||||
|
execname = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
badusage(""); /* message printed by getopt */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == stop)
|
||||||
|
badusage("need one of --start or --stop");
|
||||||
|
|
||||||
|
if (!execname && !pidfile && !userspec)
|
||||||
|
badusage("need at least one of --exec, --pidfile or --user");
|
||||||
|
|
||||||
|
if (!startas)
|
||||||
|
startas = execname;
|
||||||
|
|
||||||
|
if (start && !startas)
|
||||||
|
badusage("--start needs --exec or --startas");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
pid_is_exec(int pid, const struct stat *esb)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
sprintf(buf, "/proc/%d/exe", pid);
|
||||||
|
if (stat(buf, &sb) != 0)
|
||||||
|
return 0;
|
||||||
|
return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
pid_is_user(int pid, int uid)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
sprintf(buf, "/proc/%d", pid);
|
||||||
|
if (stat(buf, &sb) != 0)
|
||||||
|
return 0;
|
||||||
|
return (sb.st_uid == uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
pid_is_cmd(int pid, const char *name)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
FILE *f;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
sprintf(buf, "/proc/%d/stat", pid);
|
||||||
|
f = fopen(buf, "r");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
while ((c = getc(f)) != EOF && c != '(')
|
||||||
|
;
|
||||||
|
if (c != '(') {
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* this hopefully handles command names containing ')' */
|
||||||
|
while ((c = getc(f)) != EOF && c == *name)
|
||||||
|
name++;
|
||||||
|
fclose(f);
|
||||||
|
return (c == ')' && *name == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
check(int pid)
|
||||||
|
{
|
||||||
|
if (execname && !pid_is_exec(pid, &exec_stat))
|
||||||
|
return;
|
||||||
|
if (userspec && !pid_is_user(pid, user_id))
|
||||||
|
return;
|
||||||
|
if (cmdname && !pid_is_cmd(pid, cmdname))
|
||||||
|
return;
|
||||||
|
push(&found, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_pidfile(const char *name)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
f = fopen(name, "r");
|
||||||
|
if (f) {
|
||||||
|
if (fscanf(f, "%d", &pid) == 1)
|
||||||
|
check(pid);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_procfs(void)
|
||||||
|
{
|
||||||
|
DIR *procdir;
|
||||||
|
struct dirent *entry;
|
||||||
|
int foundany, pid;
|
||||||
|
|
||||||
|
procdir = opendir("/proc");
|
||||||
|
if (!procdir)
|
||||||
|
fatal("opendir /proc: %s", strerror(errno));
|
||||||
|
|
||||||
|
foundany = 0;
|
||||||
|
while ((entry = readdir(procdir)) != NULL) {
|
||||||
|
if (sscanf(entry->d_name, "%d", &pid) != 1)
|
||||||
|
continue;
|
||||||
|
foundany++;
|
||||||
|
check(pid);
|
||||||
|
}
|
||||||
|
closedir(procdir);
|
||||||
|
if (!foundany)
|
||||||
|
fatal("nothing in /proc - not mounted?");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_stop(void)
|
||||||
|
{
|
||||||
|
char what[1024];
|
||||||
|
struct pid_list *p;
|
||||||
|
|
||||||
|
if (cmdname)
|
||||||
|
strcpy(what, cmdname);
|
||||||
|
else if (execname)
|
||||||
|
strcpy(what, execname);
|
||||||
|
else if (pidfile)
|
||||||
|
sprintf(what, "process in pidfile `%s'", pidfile);
|
||||||
|
else if (userspec)
|
||||||
|
sprintf(what, "process(es) owned by `%s'", userspec);
|
||||||
|
else
|
||||||
|
fatal("internal error, please report");
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
if (quietmode <= 0)
|
||||||
|
printf("no %s found; none killed.\n", what);
|
||||||
|
exit(exitnodo);
|
||||||
|
}
|
||||||
|
for (p = found; p; p = p->next) {
|
||||||
|
if (testmode)
|
||||||
|
printf("would send signal %d to %d.\n",
|
||||||
|
signal_nr, p->pid);
|
||||||
|
else if (kill(p->pid, signal_nr) == 0)
|
||||||
|
push(&killed, p->pid);
|
||||||
|
else
|
||||||
|
printf("%s: warning: failed to kill %d: %s\n",
|
||||||
|
progname, p->pid, strerror(errno));
|
||||||
|
}
|
||||||
|
if (quietmode < 0 && killed) {
|
||||||
|
printf("stopped %s (pid", what);
|
||||||
|
for (p = killed; p; p = p->next)
|
||||||
|
printf(" %d", p->pid);
|
||||||
|
printf(").\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
progname = argv[0];
|
||||||
|
|
||||||
|
parse_options(argc, argv);
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (execname && stat(execname, &exec_stat))
|
||||||
|
fatal("stat %s: %s", execname, strerror(errno));
|
||||||
|
|
||||||
|
if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
pw = getpwnam(userspec);
|
||||||
|
if (!pw)
|
||||||
|
fatal("user `%s' not found\n", userspec);
|
||||||
|
|
||||||
|
user_id = pw->pw_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pidfile)
|
||||||
|
do_pidfile(pidfile);
|
||||||
|
else
|
||||||
|
do_procfs();
|
||||||
|
|
||||||
|
if (stop) {
|
||||||
|
do_stop();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
if (quietmode <= 0)
|
||||||
|
printf("%s already running.\n", execname);
|
||||||
|
exit(exitnodo);
|
||||||
|
}
|
||||||
|
if (testmode) {
|
||||||
|
printf("would start %s ", startas);
|
||||||
|
while (argc-- > 0)
|
||||||
|
printf("%s ", *argv++);
|
||||||
|
printf(".\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (quietmode < 0)
|
||||||
|
printf("starting %s ...\n", startas);
|
||||||
|
*--argv = startas;
|
||||||
|
execv(startas, argv);
|
||||||
|
fatal("unable to start %s: %s", startas, strerror(errno));
|
||||||
|
}
|
||||||
|
|
120
contrib/zefram-patches
Normal file
120
contrib/zefram-patches
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
Date: Mon, 14 Apr 1997 15:39:08 +0100 (BST)
|
||||||
|
From: Zefram <zefram@dcs.warwick.ac.uk>
|
||||||
|
Message-Id: <25042.199704141439@stone.dcs.warwick.ac.uk>
|
||||||
|
Subject: SysVinit patch
|
||||||
|
To: miquels@drinkel.cistron.nl
|
||||||
|
|
||||||
|
Hi. Enclosed is a patch for SysVinit that I am finding tiresome to
|
||||||
|
keep updating; you might like to fold it into your official releases.
|
||||||
|
It does the following:
|
||||||
|
|
||||||
|
* shutdown: use /etc/shutdown.allow if an option -s is given instead
|
||||||
|
of testing for a controlling tty. The tty check was inflexible and
|
||||||
|
unreliable.
|
||||||
|
|
||||||
|
* sulogin(8): refer to inittab(5) instead of inittab(4).
|
||||||
|
|
||||||
|
* sulogin: use libc passwd/shadow functions instead of home-grown ones
|
||||||
|
(there's just no point in using the special version).
|
||||||
|
|
||||||
|
* shutdown/sulogin: don't rely on the username "root" -- it's the UID
|
||||||
|
that counts.
|
||||||
|
|
||||||
|
-zefram
|
||||||
|
|
||||||
|
begin 644 initdiffs.gz
|
||||||
|
M'XL(``IG43,"`^T[:U/;R+*?E5_1>&L3&\G&#Y[FD%H")/%9)U"8G-0](44)
|
||||||
|
M>62KD"6M1K+7)YO_?KM[1K)DFP"[V:T]=2^5`FFFIZ??W=.C##W7A;H3@YS+
|
||||||
|
MJ1=X2;W=V#W8DN,T&8:SH+%?GC`+,\\V-S?O76:\CCWX9QI`:QO_=3N[W68;
|
||||||
|
M6@<'N\_J]?K].(T!+CF.8FAUH-WI-G>Z.QU:MD>;%7]X\U;+:NT!OP(T7L&6
|
||||||
|
MO/6"'!N-7;Z"3W!=3^BY=PE2./#YV48^'M^-`\?%(9J&Q)L(7M3#R9D=!UXP
|
||||||
|
MJD^$E/9(*)CKRM>O7YD#M34^U?_0UO*I>Z\3P^Z!M;>MQ$"DX>M^*R--_!KY
|
||||||
|
M-DHZC.>0H0L#2,8"G'`RL8,A^%X@<,!.8.;Y/MP*I#5((`G!]GU$D4H1R\:"
|
||||||
|
M!),>OGSY`E"7]-*[@&OWU75=7KL7^'X6R#36"&U>#'::C,/8DV)(6$E(0%)B
|
||||||
|
M*M`4$C$!3X(?CD8(X04-Q'(UQA'\%X3Q!,F8$Z(AS,8BH,TR.>..!.0@!,[>
|
||||||
|
MSFF.[`K'J_LU"_'PBI,D]NO'?E(_%3[!1S%*0@P;``,A%!7"2;R0</>.'0=G
|
||||||
|
MX20,DCCT%4^WP@]GX(8Q3$+DS0M<(HM6-)0X2"Z0RR53)DNF1V^$!N`C$:,E
|
||||||
|
MP/:^WJJ;.U9K8=?(TLG59;]^W+^JGY[UB64;:=`\6,2U$PLD)AB!'8`=17$8
|
||||||
|
MQ9Z="$`UHMJ]@+'TMD3B;)%T$OL6L324C"?"#J32EIB*>!ZB,<S&(8QME--X
|
||||||
|
M+CT4+M@L$T2#Q"O3"63H"[@3\]O0CH>H@4#IM:!2YA"N0B)URA:%^UGH`DL*
|
||||||
|
MI+7.6#AW+!I4B.<R(\IH_H.*92,J6@B:,.(A4D.7MYQZ<9(BH9HPV8">>[^A
|
||||||
|
MN'$X*9@*T>0EB@99(((0NQZRF0DOUQNB"6<:)RD"N2,'Z3'_`7E6A#J2C`&)
|
||||||
|
M1H(#&[V/*&=),]:9EXP5A"<38B028>23X2C?B46)872F)2ZAJAGI;4WM>"M.
|
||||||
|
M@ZTTF41(5ZT!YX$_)[[<A9A"*9:E*DD,:-9Q&"::GWQ/BX1"(0'1H$TY@CSF
|
||||||
|
M'`F.9^C*V23,8B]13J3C"UF^C*!%?P-767`FN2XZ]"H-^9;D)BJZMJU6>SL+
|
||||||
|
M8O_O`FM=@#1+;O![7"`W/H10D1L11131K/^[OE"2+QLWBF+5]%6X^%.,?_A`
|
||||||
|
M.>;<6SHYWRK''.,J%7"<CJBN:C6[.[O=UL'#Y9CSM'+LP&H5RA!\V\D<-
|
||||||
|
M`\L%E,`P1"$D,"(GBL-T-`;:&&ZY)""QAFDLA3\57''H=4Z7/,3!Y$U.X:.K
|
||||||
|
M#^>`*J8BJ9!,<_B$\KG$S81OSS%Y)S.!ECCHO;DZNWP'5//@\\^]?I]3.A%`
|
||||||
|
M:5POQG43^PY=F*J8A1/*=4ZH]N1?*%V"ZQKOO%]2I'2*2P>3$,N%X#:-1Q9,
|
||||||
|
M>%S^-(R]X$[X#0<M/<8"(O`5DG42W6M:>[M9(3`-/2(!C:Q:P]<OM,S%,!<D
|
||||||
|
M;E4F0Q''%%F,R@<"Z5XGD(L&/M7OXK$;.)_Q20GG,Q<I\$F7FIGY?KX.*HC7
|
||||||
|
MJ%PGA*!^UP7^&8;!BP10\%2*96@M="=\)12-I76Q7A>+6\PL8+L)2B[7U!+P
|
||||||
|
M6`./;7\M*%G37LO:R^OM[R`)^=\IBK5&LF_M=Q9^MX?E?^YX.>(@IW[9_ZXK
|
||||||
|
M7`95V`=QG,5$[(%KRV290$?CR?QQU0V7%JSWQ4S6Y(MW%$BE-PILGQ>;B\52
|
||||||
|
M[_9XARSOCM+A'%?A&KR">6243B@/4];'O6TZ%VU`E6J$ZTJ`>:Q2PT6(I'9(
|
||||||
|
M1H7')R^IMOAE_=FKO;MOM?<*XF^CS[;1:;/(AT1A:/.&08A$PA$T#_-1+</2
|
||||||
|
M6(26S0.F'D#I$=\YT.M>_PPVW4B].6,[ADV2.R>33YWVY\+$;>I^:K7W<6@M
|
||||||
|
MZ?O;5J=SD(47XI!^8U1RHGF5<-[X6+7X%E1:2A[/ZCB_M<FG)DRF,X%V.D6=
|
||||||
|
M4!*FPY)/*D6;G7BD2]C<X@4(64V<D4BB41Q5FS78.(+LK0;/G_,+\HTO1T?0
|
||||||
|
MPA%>1C]5-T+.W3`2075P>MSOGW]$:N)*C9&\_]#OU]#[ZT28@72]#]=28A&E
|
||||||
|
M,X%2+-;_'/85C8:GY*NP7&)Z@34U3@8\&V/%4G61:EE%"5N`(K8P_M04+89!
|
||||||
|
M#)/HFY^)H1<_O(#??H/"P'7PHL:$>D$J#O,E'KR$3FMY!C-459(4$,$A;,KH
|
||||||
|
M$&1DFC46ZR;-9!CY1;-A+$S",TW<EM0Z3".BJ\807YEOWO8?T&G7H+#B<X['
|
||||||
|
M=7RLE%`-O"@7\PP=V+_+0TBIY**BT?6HKY"74JJ#4!+?!HW=A'>D_RH&'C:)
|
||||||
|
M-$'?K*Y3KK&PND1W!G1O@<LS/*]S4?BODVP79BU-ZB_3Y":91X)0?AB<7=Y<
|
||||||
|
M7)Z?G`T&RV*6.GVP0BM;0S'=^E%6+-`HJ$=26ZA*)G:B0)_+I(8";*Y3*((U
|
||||||
|
M9'(3(S)X#LU?7[\^4=;?_+6YW5Q:DG%Y24F"V/-G]ES"^<\ECL@Y)U'&&`F`
|
||||||
|
M_`&75-AYFID)&EJ\IJG(,6XQHM^IYZ_?D"F55VCJ.K3F6Y,1*A\!92ZDMJ+!
|
||||||
|
MX#C:I-J*Z-Q`0@.BM`B42U/1_>'JYOWQN[-![]]GN>NL$EZD7!DM_Q+!4%M+
|
||||||
|
MP3`U-VP7,UMFO.1>3H1I_$5?+4:9D_/W@_/^&4IUMA)EJ#S,ZPPW0ICK^)&U
|
||||||
|
M?>,Z5DDEPU+R*\V8D6<;S26%9&0.5-2]T)9.&4T=U91/T;1RJJJC_`AGJYCJ
|
||||||
|
M'(L2WA3I='[!JB=PYTEWU/6ZFK&S\]<U53N!(?$`YHRK#C-*66Q_SVH?M%46
|
||||||
|
M6Y<\.GMMJ[/?7N2]3GL'!_(C.RN+_RP2"<<_(AVIPN=#-:_UBUG?<&P\E;V0
|
||||||
|
M+[HJR7#BFX1#05S2O)$GPY9:D"UF'HRA<.W43[KZU=`58C:M@0WU^E6G/!,X
|
||||||
|
MU>*&IV'6"DSQ5#<GIPA&#;6WRF)Z>PI9CTI,)EOE1_&">X99*B>.+)#A@U7-
|
||||||
|
M)B'`DT7IY*O/NPU0D6(8"LD5':X/J27I<%VJ?C($O^!!V7/G%J%@&7LJQ#AT
|
||||||
|
M@D9HW#X-T*ZG:$2TD^TX81HDFO<L.YH/9T?S@>QH/CT[FO=F1_/W94?SP>QH
|
||||||
|
MDG68#V5'LYP=V8[^8'8TGYP=U:Y/RX[FT[*C^>CL:#XJ.V90&X.;WN#D[:7.
|
||||||
|
MDN05M75P3\BB]TMC35XSGY#7S#^2U\SEO&86\YJI0F5F<\6\EIO4M_*:N9K7
|
||||||
|
MS"?E-?.[Y#5S-:^9H!E;Y#7-I8Z[.J]Q1*%S3^BNG"95J6ZK)J'.=<NL#4XO
|
||||||
|
M>J=KHB\&>5?B&4OS].,0#?8Y[H-TW-=F2[E!N>;2,YM8UV3+YOC*<R`B@%WJ
|
||||||
|
ML37;W>W._3VV?-636FS[>8L-H#%X"Z=G@Y/+WL55[_R]ND?4>/&%+#^8AG>E
|
||||||
|
MB['J?HU:M7PK5NA3CT)NR%*[%Z6/HF93(Y=\1J=C[47#D"\*551#E\IZZ]1U
|
||||||
|
MU4WUZG9-M5QQOYZZ74%KE2$U<F-/<$=9_(IY,.%.LJ8V)TGEI<B6?%6HN]/4
|
||||||
|
MJ0?7MT>(A,V!)JB7,@GY8A.J8F1!O]<_K_$MY86Z0V!191>T?T=1[?PM1/6`
|
||||||
|
M*SCW&:[S#5=PC(](U#]3']K;T-KIMMK=SNZ#KN`8[T+M"MO01`=J=EO?<(7V
|
||||||
|
M-E:HA;[+MM5I9OK^P0L</\7"\1^N$R1^8_RR-*B;34NCT6Q(0V81<&QC%%H&
|
||||||
|
MY+Y"*%>PSN66%SJ+[5RXN7GS_L--O_?J\OCR?VYNX.41[*XOISO6=C-S[!^P
|
||||||
|
MD*4[^9.W9R<_WZ#=&JV5T7>G.SR*YX-LXN)X,/AX:E2X."/#F`TKA>G!V^/3
|
||||||
|
M\X]Z6C%6*:!]U7L_>(NSZC,&FGF6M9?^A2&?+L>/H/)3]8>:UA>T&GO0VJ^C
|
||||||
|
MFNND6G@W'30JA^HP@,HXN/_P0"5A>]%Y^JHVV]JD(\^F,1#TX0`639Y]Z^>7
|
||||||
|
M3U/;3X7Z(B#A$-]@:#K8<3M8BJ2JR-W$I98F'5?1J?1+=ORC=QJ-D1E\II.6
|
||||||
|
M/@YOJ3:^\4:H&SPZ5+-[S<)XJ/Q7=?LI"6$5D#IZ>@B;6)P1>#3CQ,T=Z0T\
|
||||||
|
M4R54CB_!HI$=TN2BC;>`9)*IEOK4WMG]O#(CRU.*0>X#4JIC^K'8-UY3.S7$
|
||||||
|
MHE&&$P'Z3,37;?9P2AW'A@+<(B1D\]'LAF[D2+W<23@L3&BJ<:HT/!).*&ET
|
||||||
|
MD$88_3Y@""S-#ST2<&6K-"C'PO=74*59P[.`?3%$H\OY7MEYEO"/%@D?80TD
|
||||||
|
M)\:B3L'4&*L18^T<!YC[2?;ZZ$<3*+(-+3(LR%GAGHKUN=ZI[F@H*):7/F<S
|
||||||
|
M,7S$(9U8@$K19YR-,CFZ9\,EHP)E&7>Q%-E116R-X8Q%$<M<@'D$.^J9#/MY
|
||||||
|
M21T6V904$0XC/CK.*\@J.4)M:>[!J2)^UNM]Z(N`J.#'@+'*RX!4+M8R+H_8
|
||||||
|
MW-6;KH<W2#\;Y;/51EE=/1411.#$\RC!3).K"\,#>K4WU("8\"A:N'B81:$I
|
||||||
|
M,RAJD[03+5O0TD42%HZ2BV"5PMWL8XD`57B_E65<Z)CC#:LE#:*A+!EER86O
|
||||||
|
MBB:HBA/"P3?Z=`G-<=#6P"J4Y_`6<*61%+U<M_27C*BB+6"EGN9$<8]_K95.
|
||||||
|
M.59J:A\IH16/DD]P*?FG^]23K;*H-YGP-P1*'I:&(UY0/Q;??7U_FU3:RWSQ
|
||||||
|
MFXK/+71CO8G^+HT_<G_@S9><8%$(<"H^EG?,6U&L#7@?)OKKPMP5@E`MT,F.
|
||||||
|
M[W,I`^)1>286GQ#*.R]2+8%A&M,IDRKC+*EOZ(J!+J.8SOQJV=`97)=]$/KD
|
||||||
|
M9,G\4,TM$C2M^]3:58U-A0T91,.F"1ZD"SWO4*<?+=?*&V^Z7&[PEX8V3HN`
|
||||||
|
M,G9V'YDOJ9)4J&^COU*LG_(2Q2F:G1TG:53K@E[FNGXJQZ1!E(J^R:.OK-I[
|
||||||
|
M5FL_OZI<DOZ?7`BAKK(XL(1D:5A&-"C7Q<DGE3IJP_75SF)NN>!9S-Q;\RQ`
|
||||||
|
MRF7/8GRI\EE,%(N?PDYKZI^(B2+CG.&B:O,1D?G$I@\5N-EHPX?>*30S$;,2
|
||||||
|
ME5$5XW*FDE*)!`]GVSRU%D)8'E'J+]=DO;\BZ97W5G</S47"D[E$980&D9-*
|
||||||
|
MQE$0[GK17A0=]4=9"H`E1+R?\"4?8[(X*QE$1C?X%Q/<NBU4`JL,RFP^?CN5
|
||||||
|
M\4H2H"YW<>/#0@#^6\9?]<Y\_961^$?YK3AL@1;T=XW&:_L;!WM6IYEW^PP5
|
||||||
|
M<`V4CX/"&6/$LV!W6Z'$>D8$TVKE[?F[,R113;:4.61S_?,WU):N9!?&*P!T
|
||||||
|
M`;`T6T`]>'O6[^.P3'51K^:U"ZL.S+;5WLG_Y\%W)+AHX_>1O0KS:.+7-F3V
|
||||||
|
M]ZW.P4XN_3Q,K76*0MA1]6RK6*UR<5NH*PJA.[^_5)!K8A8&+?CM-X;(OL[!
|
||||||
|
MPI=C<35:L*TC[,J`^BI`W;1J[FF7FN[3=':LSO9"94_D<HFQ<@C5+?B_G*__
|
||||||
|
)!9>7)7O2-```
|
||||||
|
`
|
||||||
|
end
|
||||||
|
|
635
doc/Changelog
Normal file
635
doc/Changelog
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
sysvinit (2.87dsf) world; urgency=low
|
||||||
|
|
||||||
|
* Fix typos and do minor updates in the manual pages.
|
||||||
|
* Correct section of mountpoint(1).
|
||||||
|
* Document -e and -t options for telinit in init(8).
|
||||||
|
* Update address of FSF in the COPYRIGHT file.
|
||||||
|
* Document in halt(8) that -n might not disable all syncing.
|
||||||
|
Patch by Bill Nottingham and Fedora
|
||||||
|
* Adjust output from "last -x". In reboot lines, print endpoint
|
||||||
|
of uptime too. In shutdown lines print downtimes rather than
|
||||||
|
the time between downs. Fix typo in string compare in last.c.
|
||||||
|
Patch by Thomas Hood.
|
||||||
|
* Improve handling of IPv6 addresses in last. Patch from Fedora.
|
||||||
|
* Document last options in usage information, previously only
|
||||||
|
mentioned in the manual page.
|
||||||
|
* Add new option -F to last, to output full date string instead
|
||||||
|
of the short form provided by default. Patch from Olaf Dabrunz
|
||||||
|
and SuSe.
|
||||||
|
* Adjust build rules to make sure the installed binaries
|
||||||
|
are stripped.
|
||||||
|
* Increase the compiler warning level when building.
|
||||||
|
* Fix utmp/wtmp updating on 64-bit platforms. Patch by Bill
|
||||||
|
Nottingham and Fedora.
|
||||||
|
* Avoid unchecked return value from malloc() in utmpdump.
|
||||||
|
Patch from Christian 'Dr. Disk' Hechelmann and Fedora.
|
||||||
|
* Make sure to use execle and no execl when passing environment to
|
||||||
|
the new process. Patch from RedHat.
|
||||||
|
* Correct init to make sure the waiting status is preserved across
|
||||||
|
re-exec. Patch from RedHat.
|
||||||
|
* Correct init to avoid race condition when starting programs during
|
||||||
|
boot. Patch from SuSe.
|
||||||
|
* Allow 'telinit u' in runlevels 0 and 6. Patch from Thomas Hood.
|
||||||
|
* Change install rules to make pidof an absolute symlink. Patch from
|
||||||
|
Thomas Hood.
|
||||||
|
* Improve error message from init if fork() fail. Patch found in Suse.
|
||||||
|
* Add support for SE Linux capability handling. Patch from Manoj
|
||||||
|
Srivastava, adjusted to avoid aborting if SE policy was loaded in
|
||||||
|
the initrd with patch from Bill Nottingham and Fedora.
|
||||||
|
* Add -c option to pidof for only matching processes with the same
|
||||||
|
process root. Ignore -c when not running as root. Patch from
|
||||||
|
Thomas Woerner and Fedora.
|
||||||
|
* Adjust init to terminate argv0 with one 0 rather than two so that
|
||||||
|
process name can be one character longer. Patch by Kir Kolyshkin.
|
||||||
|
* Make sure bootlogd exit with non-error exit code when forking of
|
||||||
|
the child successfully.
|
||||||
|
* Add bootlogd option -s to make it possible to control the use of
|
||||||
|
fdatasync(). Patch from Thomas Hood.
|
||||||
|
* Add bootlogd option -c to tell it to create the log file if it does
|
||||||
|
not exist. Patch from Thomas Hood.
|
||||||
|
* Let bootlogd also look at ttyB* devices to work on HPPA. Patch
|
||||||
|
from Thomas Hood.
|
||||||
|
* Change init to use setenv() instead of putenv, make sure the PATH
|
||||||
|
value is usable on re-exec. Patch from Thomas Hood.
|
||||||
|
* Add usleep in killall5 after killing processes, to force the kernel
|
||||||
|
to reschedule. Patch from SuSe.
|
||||||
|
* Modify pidof to not print empty line if no pid was found.
|
||||||
|
* Modify init and sulogin to fix emergency mode's tty, making sure ^C
|
||||||
|
and ^Z work when booting with 'emergency' kernel option. Patch from
|
||||||
|
Samuel Thibault.
|
||||||
|
* Modify init to allow some time for failed opens to resolve themselves.
|
||||||
|
Patch from Bill Nottingham and Fedora.
|
||||||
|
* Modify init to shut down IDE, SCSI and SATA disks properly. Patches
|
||||||
|
from Sebastian Reichelt, Werner Fink and SuSe.
|
||||||
|
* Modify wall to use UT_LINESIZE from <utmp.h> instead of hardcoded
|
||||||
|
string lengths. Patch from SuSe.
|
||||||
|
* Change wall to make halt include hostname in output.
|
||||||
|
* Change killall to avoid killing init by mistake. Patch from SuSe.
|
||||||
|
* Change killall5 to use the exit value to report if it found any
|
||||||
|
processes to kill. Patch from Debian.
|
||||||
|
* Add option -o opmitpid to killall5, to make it possible to skip
|
||||||
|
some pids during shutdown. Based on patch from Colin Watson and
|
||||||
|
Ubuntu.
|
||||||
|
* Add references between killall5 and pidof manual pages. Patch from Debian.
|
||||||
|
* Modify killall to work better with user space file system, by
|
||||||
|
changing cwd to /proc when stopping and killing processes, and
|
||||||
|
avoiding stat() when the value isn't used. Also, lock process
|
||||||
|
pages in memory to avoid paging when user processes are stopped.
|
||||||
|
Patch from Debian and Goswin von Brederlow with changes by Kel
|
||||||
|
Modderman.
|
||||||
|
* Change shutdown to only accept flags -H and -P with the -h flag,
|
||||||
|
and document this requirement in the manual page.
|
||||||
|
* Change reboot/halt to work properly when used as a login shell.
|
||||||
|
Patch by Dale R. Worley and Fedora.
|
||||||
|
* Let sulogin fall back to the staticly linked /bin/sash if both roots
|
||||||
|
shell and /bin/sh fail to execute.
|
||||||
|
|
||||||
|
-- Petter Reinholdtsen <pere@hungry.com> Sun, 12 Jul 2009 19:58:10 +0200
|
||||||
|
|
||||||
|
sysvinit (2.86) cistron; urgency=low
|
||||||
|
|
||||||
|
* Fixed up bootlogd to read /proc/cmdline. Also keep an internal
|
||||||
|
linebuffer to process \r, \t and ^H. It is becoming useable.
|
||||||
|
* Applied trivial OWL patches
|
||||||
|
* Block signals in syslog(), since syslog() is not re-entrant
|
||||||
|
(James Olin Oden <joden@malachi.lee.k12.nc.us>, redhat bug #97534)
|
||||||
|
* Minor adjustements so that sysvinit compiles on the Hurd
|
||||||
|
* killall5 now skips kernel threads
|
||||||
|
* Inittab entries with both 'S' and other runlevels were broken.
|
||||||
|
Fix by Bryan Kadzban <bryan@kadzban.is-a-geek.net>
|
||||||
|
* Changed initreq.h to be more flexible and forwards-compatible.
|
||||||
|
* You can now through /dev/initctl set environment variables in
|
||||||
|
init that will be inherited by its children. For now, only
|
||||||
|
variables prefixed with INIT_ can be set and the maximum is
|
||||||
|
16 variables. There's also a length limit due to the size
|
||||||
|
of struct init_request, so it should be safe from abuse.
|
||||||
|
* Option -P and -H to shutdown set INIT_HALT=POWERDOWN and
|
||||||
|
INIT_HALT=HALT as environment variables as described above
|
||||||
|
* Add "mountpoint" utility.
|
||||||
|
* Slightly better algorithm in killall5.c:pidof()
|
||||||
|
* Added some patches from fedora-core (halt-usage, last -t,
|
||||||
|
sulogin-message, user-console)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 30 Jul 2004 14:14:58 +0200
|
||||||
|
|
||||||
|
sysvinit (2.85) cistron; urgency=low
|
||||||
|
|
||||||
|
* Add IPv6 support in last(1)
|
||||||
|
* Sulogin: even if the root password is empty, ask for a password-
|
||||||
|
otherwise there is no way to set a timeout.
|
||||||
|
* Removed support for ioctl.save.
|
||||||
|
* Turned of support for /etc/initrunlvl and /var/run/initrunlvl
|
||||||
|
* Fixed warts in dowall.c ("Dmitry V. Levin" <ldv@altlinux.org>)
|
||||||
|
* Fix init.c::spawn(). The "f" variable was used both as file descriptor
|
||||||
|
and waitpid(2) return code. In certain circumstances, this leads to
|
||||||
|
TIOCSCTTY with wrong file descriptor (Vladimir N. Oleynik).
|
||||||
|
* Fix fd leak in sulogin (Dmitry V. Levin).
|
||||||
|
* More error checking in all wait() calling code (Dmitry V. Levin).
|
||||||
|
* Fix argv[] initialization in spawn() (Dmitry V. Levin).
|
||||||
|
* Change strncpy to strncat in most places (Dmitry V. Levin).
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 15 Apr 2003 16:37:57 +0200
|
||||||
|
|
||||||
|
sysvinit (2.84) cistron; urgency=low
|
||||||
|
|
||||||
|
* Don't use /etc/initlvl interface for telinit; only use /dev/initctl,
|
||||||
|
and give a clear error when that fails.
|
||||||
|
* Add -i/--init command line flag to init - this tells init
|
||||||
|
'behave as system init even if you're not PID#1'. Useful for
|
||||||
|
testing in chroot/jail type environments.
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 27 Nov 2001 13:10:08 +0100
|
||||||
|
|
||||||
|
sysvinit (2.83) cistron; urgency=low
|
||||||
|
|
||||||
|
* Fix bug in shutdown where it didn't check correctly for a
|
||||||
|
virtual console when checking /etc/shutdown.allow
|
||||||
|
* Fix race condition in waitpid() [Andrea Arcangeli]
|
||||||
|
* Call closelog() after openlog()/syslog() since recent libc's
|
||||||
|
keep the logging fd open and that is fd#0 aka stdin.
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 2 Oct 2001 23:27:06 +0200
|
||||||
|
|
||||||
|
sysvinit (2.82) cistron; urgency=low
|
||||||
|
|
||||||
|
* Print out correct version number at startup.
|
||||||
|
* Fix spelling of initttab in init(8)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 23 Aug 2001 17:50:44 +0200
|
||||||
|
|
||||||
|
sysvinit (2.81) cistron; urgency=low
|
||||||
|
|
||||||
|
* Fix typo/bug in killall5/pidof, -o option failed to work since 2.79.
|
||||||
|
Reformatted source code to prevent this from happening again.
|
||||||
|
* shutdown.8: applied redhat manpage update
|
||||||
|
* sulogin: applied redhat sysvinit-2.78-sulogin-nologin.patch
|
||||||
|
* sulogin: applied redhat sysvinit-2.78-notty.patch
|
||||||
|
* sulogin: applied redhat sysvinit-2.78-sigint.patch
|
||||||
|
|
||||||
|
sysvinit (2.80) cistron; urgency=low
|
||||||
|
|
||||||
|
* Grammar/spelling fixes in shutdown.c (Christian Steinrueck)
|
||||||
|
* Don't set controlling tty for non-(sysinit,boot,single) runlevels
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 26 Jul 2001 13:26:56 +0200
|
||||||
|
|
||||||
|
sysvinit (2.79) cistron; urgency=low
|
||||||
|
|
||||||
|
* New upstream version
|
||||||
|
* several fixes to wall by Tim Robbins <fyre@box3n.gumbynet.org>
|
||||||
|
* Several extra boundary checks by Solar Designer
|
||||||
|
* Make /dev/console controlling tty
|
||||||
|
* Stricter checks on ownership of tty by mesg(1)
|
||||||
|
* Documented and restricted -n option to wall(1)
|
||||||
|
* Make it compile with glibc 2.2.2
|
||||||
|
* Document IO redirection in wall manpage (closes: #79491)
|
||||||
|
* Update README (closes: #85650)
|
||||||
|
* Fix init.8 manpage (closes: #75268)
|
||||||
|
* Fix typo in halt(8) manpage (closes: #67875)
|
||||||
|
* Check time argument of shutdown(8) for correctness (closes: #67825)
|
||||||
|
* Check for stale sessions in last(1) (Chris Wolf <cwolf@starclass.com>)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 4 Jul 2001 15:04:36 +0200
|
||||||
|
|
||||||
|
sysvinit (2.78-2) frozen unstable; urgency=high
|
||||||
|
|
||||||
|
* Change "booting" to "reloading" message at reload
|
||||||
|
* Add "-z xxx" dummy command line argument (closes: #54717)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 11 Feb 2000 12:17:54 +0100
|
||||||
|
|
||||||
|
sysvinit (2.78-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* 2.78 will be the new upstream version, I'm skipping 2.77
|
||||||
|
* Shutdown now calls sync before switching the runlevel to 0 or 6,
|
||||||
|
or before unmounting filesystems if -n was used (closes: #46461)
|
||||||
|
* Some cosmetic changes to init.c (closes: #32079)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 30 Dec 1999 20:40:23 +0100
|
||||||
|
|
||||||
|
sysvinit (2.77-2) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix last -i option
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 5 Oct 1999 21:51:50 +0200
|
||||||
|
|
||||||
|
sysvinit (2.77-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Write reboot record into utmp file as well to make rms happy
|
||||||
|
* Fork and dump core in / if SIGSEGV is received for debugging purposes
|
||||||
|
* Patch by Craig Sanders <cas@vicnet.net.au> for "last" -i option
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 4 Aug 1999 11:16:23 +0200
|
||||||
|
|
||||||
|
sysvinit (2.76-4) unstable; urgency=low
|
||||||
|
|
||||||
|
* Change dowall.c to handle Unix98 ptys correctly
|
||||||
|
* Add comment in rcS about usage of setup.sh and unconfigured.sh
|
||||||
|
* Shutdown now removes nologin file just before calling telinit
|
||||||
|
* SEGV handler now tries to continue after sleep of 30 seconds.
|
||||||
|
On a 386-class processor it also prints out the value of EIP.
|
||||||
|
* Fix for racecondition in check_init_fifo() by Richard Gooch
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Sat, 8 May 1999 17:22:57 +0200
|
||||||
|
|
||||||
|
sysvinit (2.76-3) frozen unstable; urgency=high
|
||||||
|
|
||||||
|
* Small bugfix to last.c courtesy of Danek Duvall <duvall@emufarm.ml.org>
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 12 Jan 1999 12:12:44 +0100
|
||||||
|
|
||||||
|
sysvinit (2.76-1) frozen unstable; urgency=high
|
||||||
|
|
||||||
|
* Fix bug in check_pipe() which crashes init on the Alpha.
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 3 Nov 1998 11:09:13 +0100
|
||||||
|
|
||||||
|
sysvinit (2.75-4) unstable; urgency=low
|
||||||
|
|
||||||
|
* Change sulogin password buffer to 128 characters.
|
||||||
|
* Don't print control characters in dowall.c
|
||||||
|
* Try to open getenv ("CONSOLE"), /dev/console and /dev/tty0 in order.
|
||||||
|
For backwards compatibility when you try to boot a 2.0.x kernel
|
||||||
|
with a linux > 2.1.70 /dev/console device.
|
||||||
|
* Change src/Makefile for non-debian systems (mainly, RedHat)
|
||||||
|
* Try to create /dev/initctl if not present; check every time to see
|
||||||
|
if the dev/ino of /dev/initctl has changed and re-open it. This should
|
||||||
|
help devfs a bit.
|
||||||
|
* Send SIGUSR1 to init at bootup to let it re-open /dev/initctl;
|
||||||
|
again in support of devfs.
|
||||||
|
* Moved pidof to /bin (it's only a link to killall5 anyway)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Mon, 5 Oct 1998 14:03:14 +0200
|
||||||
|
|
||||||
|
sysvinit (2.75-2) frozen unstable; urgency=medium
|
||||||
|
|
||||||
|
* Fix last.c again.
|
||||||
|
* Add check to see if /dev/initctl is really a FIFO
|
||||||
|
* In ifdown.c first down all shaper devices then the real devices
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 2 Jun 1998 22:43:01 +0200
|
||||||
|
|
||||||
|
sysvinit (2.75-1) frozen unstable; urgency=low
|
||||||
|
|
||||||
|
* Rewrote last.c to be much more memory friendly and correct,
|
||||||
|
thanks to Nick Andrew <nick@zeta.org.au> and
|
||||||
|
David Parrish <dparrish@zeta.org.au>
|
||||||
|
* Fixes bugs:
|
||||||
|
#21616: sysvinit: sulogin thinks md5 root password is bad
|
||||||
|
#21765: sysvinit: Typo in `killall5.c'
|
||||||
|
#21775: sysvinit: sysvinit does not support MD5 hashed passwords
|
||||||
|
#21990: /usr/bin/last: unnecessary memset and off-by-one bug
|
||||||
|
#22084: sysvinit 2.74-4: SIGPWR missing on sparc
|
||||||
|
#21900: init, powerfail events, and shutdown.allow
|
||||||
|
#21702: init 0 does not work as expected...
|
||||||
|
#21728: sysvinit: Typo in `init.c'
|
||||||
|
#22363: sysvinit: discrepance btw. manpage and /sbin/init
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 19 May 1998 11:02:29 +0200
|
||||||
|
|
||||||
|
sysvinit (2.74-4) frozen unstable; urgency=medium
|
||||||
|
|
||||||
|
* Add -o option to last to process libc5 utmp files.
|
||||||
|
* Buffer overflow fixed in init.c (not very serious; only exploitable
|
||||||
|
by root). Thanks to Chris Evans <chris@ferret.lmh.ox.ac.uk>
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 15 Apr 1998 17:04:33 +0200
|
||||||
|
|
||||||
|
sysvinit (2.74-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Should compile with glibc 1.99 :)
|
||||||
|
* Change behaviour of reboot(1) and halt(1) so that the default when
|
||||||
|
the runlevel can't be determined is to call shutdown.
|
||||||
|
* Added re-exec patch from Al Viro (21 Feb 1998):
|
||||||
|
'U' flag added to telinit. It forces init to re-exec itself
|
||||||
|
(passing its state through exec, certainly).
|
||||||
|
May be useful for smoother (heh) upgrades.
|
||||||
|
24 Feb 1998, AV:
|
||||||
|
did_boot made global and added to state - thanks, Miquel.
|
||||||
|
Yet another file descriptors leak - close state pipe if
|
||||||
|
re_exec fails.
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 12 Mar 1998 17:42:46 +0100
|
||||||
|
|
||||||
|
sysvinit (2.73-2) unstable; urgency=low
|
||||||
|
|
||||||
|
* Change _NSIG to NSIG for 2.1.x kernel includes.
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 8 Jan 1998 16:01:02 +0100
|
||||||
|
|
||||||
|
sysvinit (2.73-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Use siginterrupt, now that system calls are restarted by default.
|
||||||
|
Main symptom was that the sulogin timeout didn't work but there
|
||||||
|
might have been more hidden problems.
|
||||||
|
* Kill process immidiately if turned off in inittab
|
||||||
|
* Fixed sulogin check on tty arg.
|
||||||
|
* Use strerror() instead of sys_errlist
|
||||||
|
* wall now supports a '-n' option to suppress [most of] the banner.
|
||||||
|
Debian doesn't use sysvinit's wall, but apparently Redhat does.
|
||||||
|
* Add '-F' (forcefsck) option to shutdown
|
||||||
|
* Close and reopen /dev/initctl on SIGUSR1 (mainly for a /dev in ram)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Sat, 3 Jan 1998 16:32:39 +0100
|
||||||
|
|
||||||
|
sysvinit (2.72-3) unstable; urgency=low
|
||||||
|
|
||||||
|
* Add extra fork() in dowall.c to avoid hanging in rare cases
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 22 Oct 1997 14:44:00 +0200
|
||||||
|
|
||||||
|
sysvinit (2.72) unstable; urgency=low
|
||||||
|
|
||||||
|
* Applied manual page patches by Bill Hawes <whawes@star.net>. Thanks Bill!
|
||||||
|
* Applied patches to the sample Slackware scripts by
|
||||||
|
"Jonathan I. Kamens" <jik@kamens.brookline.ma.us>
|
||||||
|
* Fix halt and reboot runlevels 0 & 6 check.
|
||||||
|
* Only say "no more processes left in runlevel x" once
|
||||||
|
* Fix race condition with SIGCHLD in spawn()
|
||||||
|
(thanks to Alon Ziv <alonz@CS.Technion.AC.IL>)
|
||||||
|
* Compress all manpages (missed 2)
|
||||||
|
* Compiled for libc6
|
||||||
|
* Added poweroff patch by Roderich Schupp <rsch@ExperTeam.de>
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Sun, 12 Oct 1997 17:20:17 +0200
|
||||||
|
|
||||||
|
sysvinit (2.71-2) frozen unstable; urgency=low
|
||||||
|
|
||||||
|
* Print 2.71 instead of 2.70 on startup :)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Mon, 5 May 1997 12:45:25 +0200
|
||||||
|
|
||||||
|
sysvinit (2.71-1) frozen unstable; urgency=high
|
||||||
|
|
||||||
|
* Added code for updwtmp() in utmp.c for glibc (2.0.3)
|
||||||
|
* Fixed all programs to use functions from utmp.c and getutent()
|
||||||
|
* Do not try to clean up utmp in init itself (Bug#9022)
|
||||||
|
* Removed sync() from main loop.
|
||||||
|
* Hopefully fixes bug #8657 (shutdown signal handling)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Sat, 26 Apr 1997 19:57:27 +0200
|
||||||
|
|
||||||
|
sysvinit (2.70-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Respawn fix
|
||||||
|
* Removed StUdLy CaPs from source code
|
||||||
|
* Moved files in source archive around
|
||||||
|
* Fixes for glibc (utmp handling, signal handling).
|
||||||
|
* Fixed '-d' option to last (now also works without '-a').
|
||||||
|
* Added extra checking in last.c to prevent showing dead entries
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 7 Feb 1997 15:31:30 +0100
|
||||||
|
|
||||||
|
sysvinit (2.69-1) frozen unstable; urgency=medium
|
||||||
|
|
||||||
|
* Fixed bug that can throw X in a loop (or any other app that reads from
|
||||||
|
/dev/tty0)
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Sun, 1 Dec 1996 15:32:24 +0100
|
||||||
|
|
||||||
|
sysvinit (2.67-1) frozen unstable; urgency=high
|
||||||
|
|
||||||
|
* Fixes problem with /dev/console being controlling terminal of some
|
||||||
|
daemons
|
||||||
|
* Puts copyright file in the right place
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 15 Nov 1996 12:23:33 +0100
|
||||||
|
|
||||||
|
sysvinit (2.66-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Skipped 2.65. A development 2.65 got out by accident and is apparently
|
||||||
|
being used..
|
||||||
|
* Also compiles and runs with GNU libc (and on the Alpha)
|
||||||
|
* Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
|
||||||
|
* Fixed init panic'ing on empty lines in /etc/inittab
|
||||||
|
* Changed default PATH to include /usr/local/sbin
|
||||||
|
* Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait
|
||||||
|
This allows using ^C to interrupt some parts of eg the boot process.
|
||||||
|
* Remove old symlink in /var/log/initlvl; let init check both
|
||||||
|
/var/log and /etc itself.
|
||||||
|
|
||||||
|
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 29 Oct 1996 13:46:54 +0100
|
||||||
|
|
||||||
|
2.66 29-Oct-1996
|
||||||
|
- Skipped 2.65. A development 2.65 got out by accident and is apparently
|
||||||
|
being used..
|
||||||
|
- Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
|
||||||
|
- Fixed init panic'ing on empty lines in /etc/inittab
|
||||||
|
- Changed default PATH to include /usr/local/sbin
|
||||||
|
- Ported to Linux/Alpha and GNU libc.
|
||||||
|
- Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait.
|
||||||
|
This allows using ^C to interrupt some parts of eg the boot process.
|
||||||
|
- Remove old symlink in /var/log/initlvl; let init check both
|
||||||
|
/var/log and /etc itself.
|
||||||
|
|
||||||
|
2.64 28-Jun-1996
|
||||||
|
- Init checks CONSOLE environment variable on startup (overrides /dev/console)
|
||||||
|
- Init sets CONSOLE variable for all its children.
|
||||||
|
- Wtmp(): when zeroing out old utmp entries, keep ut_id field
|
||||||
|
- Wtmp(): try to re-use ut_id field if possible.
|
||||||
|
- SetTerm(): only read from /etc/ioctl.save if written once.
|
||||||
|
- Included start-stop-daemon, C version (source only).
|
||||||
|
- Fixed wait() for the emergency shell.
|
||||||
|
- killall5: ignore signal before doing kill(-1, pid).
|
||||||
|
|
||||||
|
2.63 14-Jun-1996
|
||||||
|
- Fixed preinst script for Debian
|
||||||
|
- Fixed init.c to become init daemon if name is init.new
|
||||||
|
- Fixed pidof to not return PIDs of shell scripts
|
||||||
|
|
||||||
|
2.62-2 09-Jun-1996
|
||||||
|
- Changed debian /etc/init.d/boot script to create a nologin file
|
||||||
|
at boot and to remove it just before going multiuser.
|
||||||
|
|
||||||
|
2.62 31-May-1996
|
||||||
|
- Decided to release a 2.62 version with a BIG WARNING about upgrading
|
||||||
|
init in it. Will send a patch to Linus for the linux/Documentation/Changes
|
||||||
|
file so that 2.62 or later is mentioned as the version to upgrade to.
|
||||||
|
- Added docs for Slackware
|
||||||
|
|
||||||
|
2.61-3 29-May-1996
|
||||||
|
- Fixed debian/etc/init.d/network for the lo device.
|
||||||
|
- Added "-xdev" to the cd /tmp && find in debian/etc/init.d/boot
|
||||||
|
- Made remove time for files in /tmp configurable.
|
||||||
|
|
||||||
|
2.61 29-Apr-1996
|
||||||
|
- Changed /etc/init.d/boot script again
|
||||||
|
- Fixed problem in init.c with trailing whitespace after entries in inittab
|
||||||
|
- Fixed killall5 problems
|
||||||
|
- Added manpage for lastb
|
||||||
|
- Added SHELL= environment variable to sulogin
|
||||||
|
- Fixed sulogin & shadow problems
|
||||||
|
- Added timeout option to sulogin
|
||||||
|
|
||||||
|
2.60-2 16-Apr-1996
|
||||||
|
- Fixed sulogin (didn't work if root wasn't first entry in shadow file)
|
||||||
|
- Fixed mesg for systems with "tty" group (such as Debian)
|
||||||
|
- Fixed nsyslog() in killall5.c
|
||||||
|
|
||||||
|
2.60 01-Apr-1996
|
||||||
|
- Fixed race condition in init.c, resulting in hanging shutdowns.
|
||||||
|
Courtesy of Max Neunhoeffer <Max.Neunhoeffer@urz.uni-heidelberg.de>.
|
||||||
|
- Fixed debian/etc/init.d/boot for swapon and mdadd
|
||||||
|
- Added architecture to debian.control
|
||||||
|
- Added manpages for rc.boot and rc.local
|
||||||
|
- Updated inittab manpage for 4-character runlevel field
|
||||||
|
- Added debian replaces for bsdutils < version_without_mesg
|
||||||
|
- Fixed init.c so that it also works with kernels 1.3.81 and up
|
||||||
|
|
||||||
|
2.59 10-Mar-1996
|
||||||
|
- Init logs less to syslog (suspected to hang in syslog() or openlog() )
|
||||||
|
- removed closelog() from init.c
|
||||||
|
- removed time check of runlevel record in halt.
|
||||||
|
- Added options to last to get hostname from ut_addr field
|
||||||
|
- Added last and mesg to installation targets
|
||||||
|
- rewrote /etc/init.d/boot a bit.
|
||||||
|
|
||||||
|
2.58-2 04-Jan-1996
|
||||||
|
- Changed etc/init.d/rc to do a stty onlcr
|
||||||
|
- Added /var/log/initrunlvl symlink
|
||||||
|
|
||||||
|
2.58-1 31-Dec-1995
|
||||||
|
- Added the latest debian files.
|
||||||
|
- Added support for 4-character id fields (if you have libc5).
|
||||||
|
- Fixed pidof (in killall5) parsing of /proc/.../stat
|
||||||
|
- Save restore GMT setting in /etc/init.d/boot
|
||||||
|
|
||||||
|
2.57d 03-Dec-1995
|
||||||
|
- Added sulogin
|
||||||
|
- Added "-b" flag to init, gives a shell before
|
||||||
|
anything else (in case the startup scripts are screwed)
|
||||||
|
- Moved fastboot to /fastboot
|
||||||
|
- Folded in Debian patches.
|
||||||
|
- Removed old scripts
|
||||||
|
- Added debian /etc/directory.
|
||||||
|
|
||||||
|
2.57c 08-Oct-1995
|
||||||
|
- Changed over to init_request (with initreq.h)
|
||||||
|
- Processes no longer killed when "process" field
|
||||||
|
changes, change takes effect after next respawn.
|
||||||
|
|
||||||
|
2.57b xx-Aug-1995
|
||||||
|
- Bugfix release for Debian and Slackware 3.0
|
||||||
|
|
||||||
|
2.57a 10-Jul-1995
|
||||||
|
- Fixed race condition init init.c wrt got_chld
|
||||||
|
- Fixed one-off for malloc in killall5.c
|
||||||
|
- Changed dowall.c
|
||||||
|
- Console code: no relink to /dev/systty on CTRL-ALT-DEL)
|
||||||
|
|
||||||
|
2.57 22-May-1995
|
||||||
|
- Changed a few things here and there, didn't
|
||||||
|
really document it :)
|
||||||
|
|
||||||
|
2.55 17-Jan-1995
|
||||||
|
- Added option to shutdown to run standalone.
|
||||||
|
|
||||||
|
2.54 12-Jan-1995
|
||||||
|
- Added GNU copyrigh to all *.[ch] files.
|
||||||
|
- added /etc/initscript
|
||||||
|
- reboot and halt now call shutdown in runlevels 1-5
|
||||||
|
- Can run from read-only root (CDROM)
|
||||||
|
|
||||||
|
2.53 10-Oct-1994
|
||||||
|
- Renamed pidof to killall5, updated all scripts to
|
||||||
|
use killall5 instead of kill -1 ....
|
||||||
|
- Rewrote scripts to use this, and some general changes.
|
||||||
|
- Added SysV command line compatibility to shutdown.
|
||||||
|
|
||||||
|
2.52 30-Aug-1994
|
||||||
|
- Added `powerfailnow' keyword, for when UPS battery is low.
|
||||||
|
- Updated `last'.
|
||||||
|
- Fixed utmp handling (wrt. CLEAN_UTMP)
|
||||||
|
TODO:
|
||||||
|
* Make last compatible with GNU/BSD (long options?)
|
||||||
|
* update powerd
|
||||||
|
* remote SIGPWR broadcast? in powerd? (with priv. port)
|
||||||
|
* remote shutdown
|
||||||
|
|
||||||
|
2.50 14-Feb-1994
|
||||||
|
- Ignores unknown command line arguments.
|
||||||
|
- Modelled more after the "real" sysVinit
|
||||||
|
- Lots of changes all over the place.
|
||||||
|
(like showing runlevel in "ps" listing, logging
|
||||||
|
runlevel into utmp file etc)
|
||||||
|
- now using "reliable" signals instead of V7 style.
|
||||||
|
- Updated all scripts. Examples are in two directories:
|
||||||
|
etc (normal) and etc-sysv (sysv style scripts).
|
||||||
|
- runlevel 0 = halt, 1 = single user, 6 = reboot.
|
||||||
|
- added support for serial console.
|
||||||
|
- updated Propaganda, manpages.
|
||||||
|
- added shutdown access control.
|
||||||
|
|
||||||
|
2.4 24-May-93
|
||||||
|
- Send out the official version into the world as
|
||||||
|
SysVinit-2.4.tar.z.
|
||||||
|
|
||||||
|
2.4g 15-May-93
|
||||||
|
- Changed init to really catch SIGPWR 'cause we
|
||||||
|
hooked up an UPS to the Linux machine. The
|
||||||
|
keyword for catching the TreeFingerSalute is
|
||||||
|
now "ctrlaltdel" instead of "power{wait,fail}".
|
||||||
|
|
||||||
|
2.4a 22-Apr-93
|
||||||
|
- Fixed last to reckognize BSD style wtmp logging.
|
||||||
|
- Changed init to write wtmp records that are
|
||||||
|
SysV compliant but are also reckognized by the
|
||||||
|
BSD last. Added a '+' option to the 'process'
|
||||||
|
field of inittab, for getties that want to do
|
||||||
|
their own utmp/wtmp housekeeping (kludge!).
|
||||||
|
- Now accepts a runlevel on the command line,
|
||||||
|
and reckognizes the 'auto' argument. (Sets the
|
||||||
|
environment variable AUTOBOOT to YES)
|
||||||
|
|
||||||
|
2.2.3 24-Mar-93
|
||||||
|
- Ripped out the 'leave' action. To difficult, and
|
||||||
|
unneeded.
|
||||||
|
- Going single user now kills _all_ processes.
|
||||||
|
- Added '-t secs' option to all commands.
|
||||||
|
- This version is stable enough to post.
|
||||||
|
|
||||||
|
2.2 02-Mar-93
|
||||||
|
- Made wait()'s asynchronous
|
||||||
|
- Changed whole thing to one big state machine
|
||||||
|
- Now using 'pseudo levels' # & * for SYSINIT & BOOT
|
||||||
|
- Added a new type of 'action', called leave. This
|
||||||
|
process will be executed when the system goes from a
|
||||||
|
runlevel specified in it's runlevel field to a
|
||||||
|
level that's not. Nice to bring down NFS and the like.
|
||||||
|
|
||||||
|
2.1 28-Jan-93
|
||||||
|
- Fixed a bug with 'boot' and 'once'.
|
||||||
|
- Check 'initdefault' for validity.
|
||||||
|
- Reckognizes "single" as command line argument.
|
||||||
|
- Retries execvp with 'sh -c exec ..' if command
|
||||||
|
is a shell script. (shouldn't execvp do this?)
|
||||||
|
- Added patches to use syslog if defined.
|
||||||
|
|
||||||
|
2.0 08-Dec-92
|
||||||
|
- Rewrote the code totally, so started with a new
|
||||||
|
version number.
|
||||||
|
- Dropped Minix support, this code now is Linux - specific.
|
||||||
|
- With TEST switch on, this init & telinit can
|
||||||
|
run standalone for test purposes.
|
||||||
|
|
||||||
|
1.3, 05-Jul-92
|
||||||
|
- Got a 386, so installed Linux. Added 'soft' reboot
|
||||||
|
to be default under linux. Fixed some typos.
|
||||||
|
|
||||||
|
1.2, 16-Jun-92
|
||||||
|
- Bugreport from Michael Haardt ; removed deadlock
|
||||||
|
and added 'waitpid' instead of 'wait' for SYSV.
|
||||||
|
|
||||||
|
1.1, 30-Apr-92
|
||||||
|
- Read manual wrong: there is no 'action' field called
|
||||||
|
process, but all entries are of type process. Every
|
||||||
|
'process' get exec'ed by /bin/sh -c 'exec command'.
|
||||||
|
- Rapidly respawning processes are caught in the act.
|
||||||
|
- _SYSV support is really Linux support,
|
||||||
|
done by poe@daimi.aau.dk on 25-Mar-92.
|
||||||
|
|
||||||
|
1.0, 01-Feb-92
|
||||||
|
- Initial version, very primitive for the Minix
|
||||||
|
operating system. Required some mods. to the
|
||||||
|
kernel.
|
||||||
|
|
56
doc/Install
Normal file
56
doc/Install
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
README for the System V style init, version 2.86
|
||||||
|
|
||||||
|
init, shutdown, halt, reboot, wall, last, mesg, runlevel,
|
||||||
|
killall5, pidof, sulogin.
|
||||||
|
|
||||||
|
All programs, files and scripts in this package are covered by
|
||||||
|
the Gnu Public License, and copyrighted by me.
|
||||||
|
|
||||||
|
If you are not using Debian and the debianized package,
|
||||||
|
you will have to install the new init by hand. You should
|
||||||
|
be able to drop the binaries into a Slackware or Redhat
|
||||||
|
system, I think.
|
||||||
|
|
||||||
|
Here is a list of preferred directories to install the progs & manpages:
|
||||||
|
|
||||||
|
wall.1, last.1, mesg.1 /usr/man/man1
|
||||||
|
inittab.5, initscript.5 /usr/man/man5
|
||||||
|
init.8, halt.8, reboot.8,
|
||||||
|
shutdown.8, powerd.8,
|
||||||
|
killall5.8, pidof.8,
|
||||||
|
runlevel.8, sulogin.8 /usr/man/man8
|
||||||
|
|
||||||
|
init /sbin/init
|
||||||
|
inittab /etc/inittab
|
||||||
|
initscript.sample /etc/initscript.sample
|
||||||
|
telinit a link (with ln(1) ) to init, either
|
||||||
|
in /bin or in /sbin.
|
||||||
|
halt /sbin/halt
|
||||||
|
reboot a link to /sbin/halt in the same directory
|
||||||
|
killall5 /sbin/killall5
|
||||||
|
pidof a link to /sbin/killall5 in the same directory.
|
||||||
|
runlevel /sbin/runlevel
|
||||||
|
shutdown /sbin/shutdown.
|
||||||
|
wall /usr/bin/wall
|
||||||
|
mesg /usr/bin/mesg
|
||||||
|
last /usr/bin/last
|
||||||
|
sulogin /sbin/sulogin
|
||||||
|
bootlogd /sbin/bootlogd
|
||||||
|
utmpdump don't install, it's just a debug thingy.
|
||||||
|
|
||||||
|
If you already _have_ a "wall" in /bin (the SLS release had, for example)
|
||||||
|
do _not_ install this wall. Chances are that the wall you are already
|
||||||
|
using is linked to /bin/write. Either first _remove_ /bin/wall before
|
||||||
|
installing the new one, or don't install the new one at all.
|
||||||
|
|
||||||
|
You might want to create a file called "/etc/shutdown.allow". Read the
|
||||||
|
manual page on shutdown to find out more about this.
|
||||||
|
|
||||||
|
Running from a read-only file system (CDROM?):
|
||||||
|
o All communication to init goes through the FIFO /dev/initctl.
|
||||||
|
There should be no problem using a read-only root file system
|
||||||
|
IF you use a Linux kernel > 1.3.66. Older kernels don't allow
|
||||||
|
writing to a FIFO on a read-only file system.
|
||||||
|
|
||||||
|
Miquel van Smoorenburg <miquels@cistron.nl>
|
81
doc/Propaganda
Normal file
81
doc/Propaganda
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Propaganda for version 2.58 of sysvinit & utilities
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
NOTE: If you use a standard distribution like Slackware, Debian
|
||||||
|
or Redhat there probably is no need to upgrade. Installing sysvinit
|
||||||
|
is only for those that upgrade their system by hand or for people
|
||||||
|
that create Linux distributions.
|
||||||
|
|
||||||
|
Sysvinit is probably the most widely used init package for Linux.
|
||||||
|
Most distributions use it. sysvinit 2.4 is really a good package,
|
||||||
|
and it was not the need for bugfixes but the need for more features
|
||||||
|
that made me work on sysvinit again.
|
||||||
|
|
||||||
|
Sysvinit is now a debian package. Debian source packages are not
|
||||||
|
special in any way -- in fact you can just unpack and compile
|
||||||
|
it on any other Linux distribution.
|
||||||
|
|
||||||
|
There was a 2.50 release of sysvinit but that was not very popular-
|
||||||
|
some of the included scripts broke with certain shells and other
|
||||||
|
minor things like that. Unfortunately I was not able to fix this
|
||||||
|
at the time because I was abroad for some time. Therefore the
|
||||||
|
description below is a comparison of 2.4 and 2.58 (actually the
|
||||||
|
same blurb as from the 2.50 announce but updated).
|
||||||
|
|
||||||
|
Wrt 2.4, some of the code has been made simpler. Everything, from
|
||||||
|
halt to reboot to single user mode is now done by shell scripts
|
||||||
|
that are executed directly by init (from /etc/inittab), so shutdown
|
||||||
|
does not kill processes anymore and then calls reboot - it merely
|
||||||
|
does some wall's to the logged in users and then switches to
|
||||||
|
runlevel 0 (halt), 1 (single user) or 6 (reboot).
|
||||||
|
|
||||||
|
I have removed support for the old style scripts; the included
|
||||||
|
example scripts are the Debian GNU/Linux distribution scripts.
|
||||||
|
This does not mean that eg the Slackware scripts stop to work;
|
||||||
|
you can probably drop this init into Slackware 3.0 without problems.
|
||||||
|
|
||||||
|
Most people have an entry in inittab to run shutdown when CTRL-ALT-DEL
|
||||||
|
is pressed; a feature has been added to shutdown to check if a
|
||||||
|
authorized user is logged in on one of the consoles to see if a
|
||||||
|
shutdown is allowed. This can be configured with an access file.
|
||||||
|
|
||||||
|
Some other general changes:
|
||||||
|
- utility "runlevel" to read the current and previous runlevel from
|
||||||
|
/var/run/utmp (it's also shown on the command line if you do a "ps").
|
||||||
|
- unreckognized options are silently ignored (such as the infamous
|
||||||
|
"ro" - mount root file system read only).
|
||||||
|
- if the file /etc/initscript is present it will be used to launch
|
||||||
|
all programs that init starts (so that you can set a generic
|
||||||
|
umask, ulimit eg for ALL processes - see initscript.sample).
|
||||||
|
- A "sulogin" program added that always asks for the root
|
||||||
|
passsword before entering single user mode.
|
||||||
|
- A "-b" flag to init that starts a shell at boot time before
|
||||||
|
_any_ other processing.
|
||||||
|
- I moved /etc/fastboot to /fastboot - wonder what that's gonna break :)
|
||||||
|
- I even updated the manpages!
|
||||||
|
|
||||||
|
Right, now some boring stuff you already know since it's the same
|
||||||
|
as in the 2.4 release:
|
||||||
|
|
||||||
|
The sysvinit package includes
|
||||||
|
|
||||||
|
* a sysv compatible /sbin/init program
|
||||||
|
* a telinit program (er, just a link to /sbin/init) to change runlevels
|
||||||
|
* a featureful shutdown
|
||||||
|
* halt and reboot to assist shutdown
|
||||||
|
* a very forgiving last utility
|
||||||
|
* the wall & mesg programs (not installed by default)
|
||||||
|
* manpages for everything
|
||||||
|
|
||||||
|
The new sysv init can be found on:
|
||||||
|
|
||||||
|
tsx-11.mit.edu:/pub/linux/sources/sbin as sysvinit-2.58-1.tar.gz
|
||||||
|
sunsite.unc.edu:/pub/Linux/system/Daemons as sysvinit-2.58-1.tar.gz
|
||||||
|
|
||||||
|
It will be moved there in a few days, in the mean time it is
|
||||||
|
probably in the Incoming directory.
|
||||||
|
|
||||||
|
Mike. (02-Jan-1996)
|
||||||
|
|
19
doc/bootlogd.README
Normal file
19
doc/bootlogd.README
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
bootlogd: a way to capture all console output during bootup
|
||||||
|
in a logfile.
|
||||||
|
|
||||||
|
- bootlogd opens /dev/console and finds out what the real console is
|
||||||
|
with an ioctl() if TIOCCONS is available
|
||||||
|
- otherwise bootlogd tries to parse /proc/cmdline for console=
|
||||||
|
kernel command line arguments
|
||||||
|
- then opens the (most probable) real console
|
||||||
|
- allocates a pty pair
|
||||||
|
- redirects console I/O to the pty pair
|
||||||
|
- then goes in a loop reading from the pty, writing to the real
|
||||||
|
console and a logfile as soon as a r/w partition is available,
|
||||||
|
buffering in memory until then.
|
||||||
|
|
||||||
|
As soon as bootlogd exits or gets killed, the pty is closed and the
|
||||||
|
redirection will be automatically undone by the kernel. So that's
|
||||||
|
pretty safe.
|
||||||
|
|
14
doc/sysvinit-2.86.lsm
Normal file
14
doc/sysvinit-2.86.lsm
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Begin3
|
||||||
|
Title: sysvinit and utilities
|
||||||
|
Version: 2.86
|
||||||
|
Entered-Date: 30JUL2004
|
||||||
|
Description: This is the Linux System V init.
|
||||||
|
This version can be compiled with glibc 2.0.6 and up.
|
||||||
|
Author: miquels@cistron.nl (Miquel van Smoorenburg)
|
||||||
|
Primary-Site: ftp.cistron.nl /pub/people/miquels/software
|
||||||
|
92K sysvinit-2.86.tar.gz
|
||||||
|
Alternate-Site: sunsite.unc.edu /pub/Linux/system/daemons/init
|
||||||
|
92K sysvinit-2.86.tar.gz
|
||||||
|
Copying-Policy: GPL
|
||||||
|
Keywords: init shutdown halt reboot
|
||||||
|
End
|
72
man/bootlogd.8
Normal file
72
man/bootlogd.8
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH BOOTLOGD 8 "Jul 21, 2003" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
bootlogd \- record boot messages
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /sbin/bootlogd
|
||||||
|
.RB [ \-c ]
|
||||||
|
.RB [ \-d ]
|
||||||
|
.RB [ \-r ]
|
||||||
|
.RB [ \-s ]
|
||||||
|
.RB [ \-v ]
|
||||||
|
.RB [ " -l logfile " ]
|
||||||
|
.RB [ " -p pidfile " ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBBootlogd\fP runs in the background and copies all strings sent to the
|
||||||
|
\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
|
||||||
|
the messages will be kept in memory until it is.
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP \fB\-d\fP
|
||||||
|
Do not fork and run in the background.
|
||||||
|
.IP \fB\-c\fP
|
||||||
|
Attempt to write to the logfile even if it does not yet exist.
|
||||||
|
Without this option,
|
||||||
|
.B bootlogd
|
||||||
|
will wait for the logfile to appear before attempting to write to it.
|
||||||
|
This behavior prevents bootlogd from creating logfiles under mount points.
|
||||||
|
.IP \fB\-r\fP
|
||||||
|
If there is an existing logfile called \fIlogfile\fP rename it to
|
||||||
|
\fIlogfile~\fP unless \fIlogfile~\fP already exists.
|
||||||
|
.IP \fB\-s\fP
|
||||||
|
Ensure that the data is written to the file after each line by calling
|
||||||
|
.BR fdatasync (3).
|
||||||
|
This will slow down a
|
||||||
|
.BR fsck (8)
|
||||||
|
process running in parallel.
|
||||||
|
.IP \fB\-v\fP
|
||||||
|
Show version.
|
||||||
|
.IP "\fB\-l\fP \fIlogfile\fP"
|
||||||
|
Log to this logfile. The default is \fI/var/log/boot\fP.
|
||||||
|
.IP "\fB\-p\fP \fIpidfile\fP"
|
||||||
|
Put process-id in this file. The default is no pidfile.
|
||||||
|
.SH BUGS
|
||||||
|
Bootlogd works by redirecting the console output from the console device.
|
||||||
|
(Consequently \fBbootlogd\fP requires PTY support in the kernel configuration.)
|
||||||
|
It copies that output to the real console device and to a log file.
|
||||||
|
There is no standard way of ascertaining the real console device
|
||||||
|
if you have a new-style \fI/dev/console\fP device (major 5, minor 1)
|
||||||
|
so \fBbootlogd\fP parses the kernel command line looking for
|
||||||
|
\fBconsole=...\fP lines and deduces the real console device from that.
|
||||||
|
If that syntax is ever changed by the kernel, or a console type is used that
|
||||||
|
\fBbootlogd\fP does not know about then \fBbootlogd\fP will not work.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR dmesg (8), fdatasync (3).
|
52
man/bootlogd.8.todo
Normal file
52
man/bootlogd.8.todo
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-1999 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH BOOTLOGD 8 "Aug 24, 1999" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
bootlogd \- record boot messages
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /sbin/bootlogd
|
||||||
|
.RB [ \-d ]
|
||||||
|
.RB [ \-r ]
|
||||||
|
.RB [ \-v ]
|
||||||
|
.RB [ " -l logfile " ]
|
||||||
|
.RB [ " -p pidfile " ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBBootlogd\fP runs in the background and copies all strings sent to the
|
||||||
|
\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
|
||||||
|
the messages will be buffered in-memory until it is.
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP \fB\-d\fP
|
||||||
|
Do not fork and run in the background.
|
||||||
|
.IP \fB\-r\fP
|
||||||
|
If there is an existing logfile called \fIlogfile\fP rename it to
|
||||||
|
\fIlogfile~\fP unless \fIlogfile~\fP already exists.
|
||||||
|
.IP \fB\-v\fP
|
||||||
|
Show version.
|
||||||
|
.IP \fB\-l logfile\fP
|
||||||
|
Log to this logfile. The default is \fI/var/log/boot.log\fP.
|
||||||
|
.IP \fB\-p pidfile\fP
|
||||||
|
Put process-id in this file. The default is no pidfile.
|
||||||
|
.SH NOTES
|
||||||
|
There is no standard way to find out the real console device if you have
|
||||||
|
a new-style \fI/dev/console\fP device (major 5, minor 1). \fBBootlogd\fP
|
||||||
|
might have some difficulties to do this, especially under very old
|
||||||
|
or very new kernels.
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR dmesg (8)
|
120
man/halt.8
Normal file
120
man/halt.8
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.\"{{{}}}
|
||||||
|
.\"{{{ Title
|
||||||
|
.TH HALT 8 "Nov 6, 2001" "" "Linux System Administrator's Manual"
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Name
|
||||||
|
.SH NAME
|
||||||
|
halt, reboot, poweroff \- stop the system.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Synopsis
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /sbin/halt
|
||||||
|
.RB [ \-n ]
|
||||||
|
.RB [ \-w ]
|
||||||
|
.RB [ \-d ]
|
||||||
|
.RB [ \-f ]
|
||||||
|
.RB [ \-i ]
|
||||||
|
.RB [ \-p ]
|
||||||
|
.RB [ \-h ]
|
||||||
|
.br
|
||||||
|
.B /sbin/reboot
|
||||||
|
.RB [ \-n ]
|
||||||
|
.RB [ \-w ]
|
||||||
|
.RB [ \-d ]
|
||||||
|
.RB [ \-f ]
|
||||||
|
.RB [ \-i ]
|
||||||
|
.br
|
||||||
|
.B /sbin/poweroff
|
||||||
|
.RB [ \-n ]
|
||||||
|
.RB [ \-w ]
|
||||||
|
.RB [ \-d ]
|
||||||
|
.RB [ \-f ]
|
||||||
|
.RB [ \-i ]
|
||||||
|
.RB [ \-h ]
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Description
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBHalt\fP notes that the system is being brought down in the file
|
||||||
|
\fI/var/log/wtmp\fP, and then either tells the kernel to halt, reboot or
|
||||||
|
power-off the system.
|
||||||
|
.PP
|
||||||
|
If \fBhalt\fP or \fBreboot\fP is called when the system is
|
||||||
|
\fInot\fP in runlevel \fB0\fP or \fB6\fP, in other words when it's running
|
||||||
|
normally, \fBshutdown\fP will be invoked instead (with the \fB-h\fP
|
||||||
|
or \fB-r\fP flag). For more info see the \fBshutdown\fP(8)
|
||||||
|
manpage.
|
||||||
|
.PP
|
||||||
|
The rest of this manpage describes the behaviour in runlevels 0
|
||||||
|
and 6, that is when the systems shutdown scripts are being run.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Options
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP \fB\-n\fP
|
||||||
|
Don't sync before reboot or halt. Note that the kernel and storage
|
||||||
|
drivers may still sync.
|
||||||
|
.IP \fB\-w\fP
|
||||||
|
Don't actually reboot or halt but only write the wtmp record
|
||||||
|
(in the \fI/var/log/wtmp\fP file).
|
||||||
|
.IP \fB\-d\fP
|
||||||
|
Don't write the wtmp record. The \fB\-n\fP flag implies \fB\-d\fP.
|
||||||
|
.IP \fB\-f\fP
|
||||||
|
Force halt or reboot, don't call \fBshutdown\fP(8).
|
||||||
|
.IP \fB\-i\fP
|
||||||
|
Shut down all network interfaces just before halt or reboot.
|
||||||
|
.IP \fB\-h\fP
|
||||||
|
Put all hard drives on the system in stand-by mode just before halt or power-off.
|
||||||
|
.IP \fB\-p\fP
|
||||||
|
When halting the system, switch off the power. This is the default when halt is
|
||||||
|
called as \fBpoweroff\fP.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Diagnostics
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
If you're not the superuser, you will get the message `must be superuser'.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Notes
|
||||||
|
.SH NOTES
|
||||||
|
Under older \fBsysvinit\fP releases , \fBreboot\fP and \fBhalt\fP should
|
||||||
|
never be called directly. From release 2.74 on \fBhalt\fP and \fBreboot\fP
|
||||||
|
invoke \fBshutdown\fP(8) if the system is not in runlevel 0 or 6. This
|
||||||
|
means that if \fBhalt\fP or \fBreboot\fP cannot find out the current
|
||||||
|
runlevel (for example, when \fI/var/run/utmp\fP hasn't been initialized
|
||||||
|
correctly) \fBshutdown\fP will be called, which might not be what you want.
|
||||||
|
Use the \fB-f\fP flag if you want to do a hard \fBhalt\fP or \fBreboot\fP.
|
||||||
|
.PP
|
||||||
|
The \fB-h\fP flag puts all hard disks in standby mode just before halt
|
||||||
|
or power-off. Right now this is only implemented for IDE drives. A side
|
||||||
|
effect of putting the drive in stand-by mode is that the write cache
|
||||||
|
on the disk is flushed. This is important for IDE drives, since the
|
||||||
|
kernel doesn't flush the write cache itself before power-off.
|
||||||
|
.PP
|
||||||
|
The \fBhalt\fP program uses /proc/ide/hd* to find all IDE disk devices,
|
||||||
|
which means that \fI/proc\fP needs to be mounted when \fBhalt\fP or
|
||||||
|
\fBpoweroff\fP is called or the \fB-h\fP switch will do nothing.
|
||||||
|
.PP
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Author
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ See also
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR shutdown (8),
|
||||||
|
.BR init (8)
|
||||||
|
.\"}}}
|
313
man/init.8
Normal file
313
man/init.8
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.\"{{{}}}
|
||||||
|
.\"{{{ Title
|
||||||
|
.TH INIT 8 "29 Jul 2004" "" "Linux System Administrator's Manual"
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Name
|
||||||
|
.SH NAME
|
||||||
|
init, telinit \- process control initialization
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Synopsis
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /sbin/init
|
||||||
|
.RB [ " -a " ]
|
||||||
|
.RB [ " -s " ]
|
||||||
|
.RB [ " -b " ]
|
||||||
|
[ \fB\-z\fP \fIxxx\fP ]
|
||||||
|
.RB [ " 0123456Ss " ]
|
||||||
|
.br
|
||||||
|
.B /sbin/telinit
|
||||||
|
[ \fB\-t\fP \fISECONDS\fP ]
|
||||||
|
.RB [ " 0123456sSQqabcUu " ]
|
||||||
|
.br
|
||||||
|
.B /sbin/telinit
|
||||||
|
[ \fB\-e\fP \fIVAR\fP[\fB=\fP\fIVAL\fP] ]
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Description
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.\"{{{ init
|
||||||
|
.SS Init
|
||||||
|
.B Init
|
||||||
|
is the parent of all processes. Its primary role is to create processes
|
||||||
|
from a script stored in the file \fB/etc/inittab\fP (see
|
||||||
|
\fIinittab\fP(5)). This file usually has entries which cause \fBinit\fP
|
||||||
|
to spawn \fBgetty\fPs on each line that users can log in. It also
|
||||||
|
controls autonomous processes required by any particular system.
|
||||||
|
.PP
|
||||||
|
.\"{{{ Runlevels
|
||||||
|
.SH RUNLEVELS
|
||||||
|
A \fIrunlevel\fP is a software configuration of the system which allows
|
||||||
|
only a selected group of processes to exist. The processes spawned by
|
||||||
|
\fBinit\fP for each of these runlevels are defined in the
|
||||||
|
\fB/etc/inittab\fP file. \fBInit\fP can be in one of eight runlevels:
|
||||||
|
\fB0\(en6\fP and \fBS\fP or \fBs\fP. The runlevel is
|
||||||
|
changed by having a privileged user run \fBtelinit\fP, which sends
|
||||||
|
appropriate signals to \fBinit\fP, telling it which runlevel to change
|
||||||
|
to.
|
||||||
|
.PP
|
||||||
|
Runlevels \fB0\fP, \fB1\fP, and \fB6\fP are reserved. Runlevel 0 is used to
|
||||||
|
halt the system, runlevel 6 is used to reboot the system, and runlevel
|
||||||
|
1 is used to get the system down into single user mode. Runlevel \fBS\fP
|
||||||
|
is not really meant to be used directly, but more for the scripts that are
|
||||||
|
executed when entering runlevel 1. For more information on this,
|
||||||
|
see the manpages for \fBshutdown\fP(8) and \fBinittab\fP(5).
|
||||||
|
.PP
|
||||||
|
Runlevels 7-9 are also valid, though not really documented. This is
|
||||||
|
because "traditional" Unix variants don't use them.
|
||||||
|
In case you're curious, runlevels \fIS\fP and \fIs\fP are in fact the same.
|
||||||
|
Internally they are aliases for the same runlevel.
|
||||||
|
.\"}}}
|
||||||
|
.PP
|
||||||
|
.SH BOOTING
|
||||||
|
After \fBinit\fP is invoked as the last step of the kernel boot sequence,
|
||||||
|
it looks for the file \fB/etc/inittab\fP to see if there is an entry of the
|
||||||
|
type \fBinitdefault\fP (see \fIinittab\fP(5)). The \fBinitdefault\fP entry
|
||||||
|
determines the initial runlevel of the system. If there is no such
|
||||||
|
entry (or no \fB/etc/inittab\fP at all), a runlevel must be
|
||||||
|
entered at the system console.
|
||||||
|
.PP
|
||||||
|
Runlevel \fBS\fP or \fBs\fP bring the system to single user mode
|
||||||
|
and do not require an \fB/etc/inittab\fP file. In single user mode,
|
||||||
|
\fB/sbin/sulogin\fP is invoked on \fB/dev/console\fP.
|
||||||
|
.PP
|
||||||
|
When entering single user mode, \fBinit\fP initializes the consoles
|
||||||
|
\fBstty\fP settings to sane values. Clocal mode is set. Hardware
|
||||||
|
speed and handshaking are not changed.
|
||||||
|
.PP
|
||||||
|
When entering a multi-user mode for the first time, \fBinit\fP performs the
|
||||||
|
\fBboot\fP and \fBbootwait\fP entries to allow file systems to be
|
||||||
|
mounted before users can log in. Then all entries matching the runlevel
|
||||||
|
are processed.
|
||||||
|
.PP
|
||||||
|
When starting a new process, \fBinit\fP first checks whether the file
|
||||||
|
\fI/etc/initscript\fP exists. If it does, it uses this script to
|
||||||
|
start the process.
|
||||||
|
.PP
|
||||||
|
Each time a child terminates, \fBinit\fP records the fact and the reason
|
||||||
|
it died in \fB/var/run/utmp\fP and \fB/var/log/wtmp\fP,
|
||||||
|
provided that these files exist.
|
||||||
|
.SH CHANGING RUNLEVELS
|
||||||
|
After it has spawned all of the processes specified, \fBinit\fP waits
|
||||||
|
for one of its descendant processes to die, a powerfail signal, or until
|
||||||
|
it is signaled by \fBtelinit\fP to change the system's runlevel.
|
||||||
|
When one of the above three conditions occurs, it re-examines
|
||||||
|
the \fB/etc/inittab\fP file. New entries can be added to this file at
|
||||||
|
any time. However, \fBinit\fP still waits for one of the above three
|
||||||
|
conditions to occur. To provide for an instantaneous response, the
|
||||||
|
\fBtelinit Q\fP or \fBq\fP command can wake up \fBinit\fP to re-examine the
|
||||||
|
\fB/etc/inittab\fP file.
|
||||||
|
.PP
|
||||||
|
If \fBinit\fP is not in single user mode and receives a powerfail
|
||||||
|
signal (SIGPWR), it reads the file \fB/etc/powerstatus\fP. It then starts
|
||||||
|
a command based on the contents of this file:
|
||||||
|
.IP F(AIL)
|
||||||
|
Power is failing, UPS is providing the power. Execute the \fBpowerwait\fP
|
||||||
|
and \fBpowerfail\fP entries.
|
||||||
|
.IP O(K)
|
||||||
|
The power has been restored, execute the \fBpowerokwait\fP entries.
|
||||||
|
.IP L(OW)
|
||||||
|
The power is failing and the UPS has a low battery. Execute the
|
||||||
|
\fBpowerfailnow\fP entries.
|
||||||
|
.PP
|
||||||
|
If /etc/powerstatus doesn't exist or contains anything else then the
|
||||||
|
letters \fBF\fP, \fBO\fP or \fBL\fP, init will behave as if it has read
|
||||||
|
the letter \fBF\fP.
|
||||||
|
.PP
|
||||||
|
Usage of \fBSIGPWR\fP and \fB/etc/powerstatus\fP is discouraged. Someone
|
||||||
|
wanting to interact with \fBinit\fP should use the \fB/dev/initctl\fP
|
||||||
|
control channel - see the source code of the \fBsysvinit\fP package
|
||||||
|
for more documentation about this.
|
||||||
|
.PP
|
||||||
|
When \fBinit\fP is requested to change the runlevel, it sends the
|
||||||
|
warning signal \s-1\fBSIGTERM\fP\s0 to all processes that are undefined
|
||||||
|
in the new runlevel. It then waits 5 seconds before forcibly
|
||||||
|
terminating these processes via the \s-1\fBSIGKILL\fP\s0 signal.
|
||||||
|
Note that \fBinit\fP assumes that all these processes (and their
|
||||||
|
descendants) remain in the same process group which \fBinit\fP
|
||||||
|
originally created for them. If any process changes its process group
|
||||||
|
affiliation it will not receive these signals. Such processes need to
|
||||||
|
be terminated separately.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ telinit
|
||||||
|
.SH TELINIT
|
||||||
|
\fB/sbin/telinit\fP is linked to \fB/sbin/init\fP. It takes a
|
||||||
|
one-character argument and signals \fBinit\fP to perform the appropriate
|
||||||
|
action. The following arguments serve as directives to
|
||||||
|
\fBtelinit\fP:
|
||||||
|
.IP "\fB0\fP,\fB1\fP,\fB2\fP,\fB3\fP,\fB4\fP,\fB5\fP or \fB6\fP"
|
||||||
|
tell \fBinit\fP to switch to the specified run level.
|
||||||
|
.IP \fBa\fP,\fBb\fP,\fBc\fP
|
||||||
|
tell \fBinit\fP to process only those \fB/etc/inittab\fP file
|
||||||
|
entries having runlevel \fBa\fP,\fBb\fP or \fBc\fP.
|
||||||
|
.IP "\fBQ\fP or \fBq\fP"
|
||||||
|
tell \fBinit\fP to re-examine the \fB/etc/inittab\fP file.
|
||||||
|
.IP "\fBS\fP or \fBs\fP"
|
||||||
|
tell \fBinit\fP to switch to single user mode.
|
||||||
|
.IP "\fBU\fP or \fBu\fP"
|
||||||
|
tell \fBinit\fP to re-execute itself (preserving the state). No re-examining of
|
||||||
|
\fB/etc/inittab\fP file happens. Run level should be one of
|
||||||
|
\fBSs0123456\fP
|
||||||
|
otherwise request would be silently ignored.
|
||||||
|
.PP
|
||||||
|
\fBtelinit\fP can tell \fBinit\fP how long it should wait
|
||||||
|
between sending processes the SIGTERM and SIGKILL signals. The default
|
||||||
|
is 5 seconds, but this can be changed with the \fB-t\fP option.
|
||||||
|
.PP
|
||||||
|
\fBtelinit -e\fP tells \fBinit\fP to change the environment
|
||||||
|
for processes it spawns.
|
||||||
|
The argument of \fB-e\fP is either of the form \fIVAR\fP=\fIVAL\fP
|
||||||
|
which sets variable \fIVAR\fP to value \fIVAL\fP,
|
||||||
|
or of the form \fIVAR\fP
|
||||||
|
(without an equality sign)
|
||||||
|
which unsets variable \fIVAR\fP.
|
||||||
|
.PP
|
||||||
|
\fBtelinit\fP can be invoked only by users with appropriate
|
||||||
|
privileges.
|
||||||
|
.PP
|
||||||
|
The \fBinit\fP binary checks if it is \fBinit\fP or \fBtelinit\fP by looking
|
||||||
|
at its \fIprocess id\fP; the real \fBinit\fP's process id is always \fB1\fP.
|
||||||
|
From this it follows that instead of calling \fBtelinit\fP one can also
|
||||||
|
just use \fBinit\fP instead as a shortcut.
|
||||||
|
.\"}}}
|
||||||
|
.\"}}}
|
||||||
|
.SH ENVIRONMENT
|
||||||
|
\fBInit\fP sets the following environment variables for all its children:
|
||||||
|
.IP \fBPATH\fP
|
||||||
|
\fI/bin:/usr/bin:/sbin:/usr/sbin\fP
|
||||||
|
.IP \fBINIT_VERSION\fP
|
||||||
|
As the name says. Useful to determine if a script runs directly from \fBinit\fP.
|
||||||
|
.IP \fBRUNLEVEL\fP
|
||||||
|
The current system runlevel.
|
||||||
|
.IP \fBPREVLEVEL\fP
|
||||||
|
The previous runlevel (useful after a runlevel switch).
|
||||||
|
.IP \fBCONSOLE\fP
|
||||||
|
The system console. This is really inherited from the kernel; however
|
||||||
|
if it is not set \fBinit\fP will set it to \fB/dev/console\fP by default.
|
||||||
|
.SH BOOTFLAGS
|
||||||
|
It is possible to pass a number of flags to \fBinit\fP from the
|
||||||
|
boot monitor (eg. LILO). \fBInit\fP accepts the following flags:
|
||||||
|
.TP 0.5i
|
||||||
|
.B -s, S, single
|
||||||
|
Single user mode boot. In this mode \fI/etc/inittab\fP is
|
||||||
|
examined and the bootup rc scripts are usually run before
|
||||||
|
the single user mode shell is started.
|
||||||
|
.PP
|
||||||
|
.TP 0.5i
|
||||||
|
.B 1-5
|
||||||
|
Runlevel to boot into.
|
||||||
|
.PP
|
||||||
|
.TP 0.5i
|
||||||
|
.B -b, emergency
|
||||||
|
Boot directly into a single user shell without running any
|
||||||
|
other startup scripts.
|
||||||
|
.PP
|
||||||
|
.TP 0.5i
|
||||||
|
.B -a, auto
|
||||||
|
The LILO boot loader adds the word "auto" to the command line if it
|
||||||
|
booted the kernel with the default command line (without user intervention).
|
||||||
|
If this is found \fBinit\fP sets the "AUTOBOOT" environment
|
||||||
|
variable to "yes". Note that you cannot use this for any security
|
||||||
|
measures - of course the user could specify "auto" or \-a on the
|
||||||
|
command line manually.
|
||||||
|
.PP
|
||||||
|
.TP 0.5i
|
||||||
|
.BI "-z " xxx
|
||||||
|
The argument to \fB-z\fP is ignored. You can use this to expand the command
|
||||||
|
line a bit, so that it takes some more space on the stack. \fBInit\fP
|
||||||
|
can then manipulate the command line so that \fBps\fP(1) shows
|
||||||
|
the current runlevel.
|
||||||
|
.PP
|
||||||
|
.SH INTERFACE
|
||||||
|
Init listens on a \fIfifo\fP in /dev, \fI/dev/initctl\fP, for messages.
|
||||||
|
\fBTelinit\fP uses this to communicate with init. The interface is not
|
||||||
|
very well documented or finished. Those interested should study the
|
||||||
|
\fIinitreq.h\fP file in the \fIsrc/\fP subdirectory of the \fBinit\fP
|
||||||
|
source code tar archive.
|
||||||
|
.SH SIGNALS
|
||||||
|
Init reacts to several signals:
|
||||||
|
.TP 0.5i
|
||||||
|
.B SIGHUP
|
||||||
|
Has the same effect as \fBtelinit q\fP.
|
||||||
|
.PP
|
||||||
|
.TP 0.5i
|
||||||
|
.B SIGUSR1
|
||||||
|
On receipt of this signals, init closes and re-opens its control fifo,
|
||||||
|
\fB/dev/initctl\fP. Useful for bootscripts when /dev is remounted.
|
||||||
|
.TP 0.5i
|
||||||
|
.B SIGINT
|
||||||
|
Normally the kernel sends this signal to init when CTRL-ALT-DEL is
|
||||||
|
pressed. It activates the \fIctrlaltdel\fP action.
|
||||||
|
.TP 0.5i
|
||||||
|
.B SIGWINCH
|
||||||
|
The kernel sends this signal when the \fIKeyboardSignal\fP key is hit.
|
||||||
|
It activates the \fIkbrequest\fP action.
|
||||||
|
\"{{{ Conforming to
|
||||||
|
.SH CONFORMING TO
|
||||||
|
\fBInit\fP is compatible with the System V init. It works closely
|
||||||
|
together with the scripts in the directories
|
||||||
|
\fI/etc/init.d\fP and \fI/etc/rc{runlevel}.d\fP.
|
||||||
|
If your system uses this convention, there should be a \fIREADME\fP
|
||||||
|
file in the directory \fI/etc/init.d\fP explaining how these scripts work.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Files
|
||||||
|
.SH FILES
|
||||||
|
.nf
|
||||||
|
/etc/inittab
|
||||||
|
/etc/initscript
|
||||||
|
/dev/console
|
||||||
|
/var/run/utmp
|
||||||
|
/var/log/wtmp
|
||||||
|
/dev/initctl
|
||||||
|
.fi
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Warnings
|
||||||
|
.SH WARNINGS
|
||||||
|
\fBInit\fP assumes that processes and descendants of processes
|
||||||
|
remain in the same process group which was originally created
|
||||||
|
for them. If the processes change their group, \fBinit\fP can't
|
||||||
|
kill them and you may end up with two processes reading from one
|
||||||
|
terminal line.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Diagnostics
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
If \fBinit\fP finds that it is continuously respawning an entry
|
||||||
|
more than 10 times in 2 minutes, it will assume that there is an error
|
||||||
|
in the command string, generate an error message on the system console,
|
||||||
|
and refuse to respawn this entry until either 5 minutes has elapsed or
|
||||||
|
it receives a signal. This prevents it from eating up system resources
|
||||||
|
when someone makes a typographical error in the \fB/etc/inittab\fP file
|
||||||
|
or the program for the entry is removed.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Author
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg (miquels@cistron.nl), initial manual
|
||||||
|
page by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ See also
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR getty (1),
|
||||||
|
.BR login (1),
|
||||||
|
.BR sh (1),
|
||||||
|
.BR runlevel (8),
|
||||||
|
.BR shutdown(8),
|
||||||
|
.BR kill (1),
|
||||||
|
.BR inittab (5),
|
||||||
|
.BR initscript (5),
|
||||||
|
.BR utmp (5)
|
||||||
|
.\"}}}
|
72
man/initscript.5
Normal file
72
man/initscript.5
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH INITSCRIPT 5 "July 10, 2003" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
initscript \- script that executes inittab commands.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
/bin/sh /etc/initscript id runlevels action process
|
||||||
|
.SH DESCRIPTION
|
||||||
|
When the shell script \fI/etc/initscript\fP is present, \fBinit\fP
|
||||||
|
will use it to execute the commands from \fIinittab\fP.
|
||||||
|
This script can be used to set things like \fBulimit\fP and
|
||||||
|
\fBumask\fP default values for every process.
|
||||||
|
.SH EXAMPLES
|
||||||
|
This is a sample initscript, which might be installed on your
|
||||||
|
system as \fI/etc/initscript.sample\fP.
|
||||||
|
.RS
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ne 7
|
||||||
|
|
||||||
|
#
|
||||||
|
# initscript Executed by init(8) for every program it
|
||||||
|
# wants to spawn like this:
|
||||||
|
#
|
||||||
|
# /bin/sh /etc/initscript <id> <level> <action> <process>
|
||||||
|
#
|
||||||
|
|
||||||
|
# Set umask to safe level, and enable core dumps.
|
||||||
|
umask 022
|
||||||
|
ulimit -c 2097151
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
# Increase the hard file descriptor limit for all processes
|
||||||
|
# to 8192. The soft limit is still 1024, but any unprivileged
|
||||||
|
# process can increase its soft limit up to the hard limit
|
||||||
|
# with "ulimit -Sn xxx" (needs a 2.2.13 or later Linux kernel).
|
||||||
|
ulimit -Hn 8192
|
||||||
|
|
||||||
|
# Execute the program.
|
||||||
|
eval exec "$4"
|
||||||
|
|
||||||
|
.sp
|
||||||
|
.RE
|
||||||
|
.SH NOTES
|
||||||
|
This script is not meant as startup script for daemons or somesuch.
|
||||||
|
It has nothing to do with a \fIrc.local\fP style script. It's just
|
||||||
|
a handler for things executed from \fB/etc/inittab\fP. Experimenting
|
||||||
|
with this can make your system un(re)bootable.
|
||||||
|
.RE
|
||||||
|
.SH FILES
|
||||||
|
/etc/inittab,
|
||||||
|
/etc/initscript.
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg ,<miquels@cistron.nl>
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
init(8), inittab(5).
|
265
man/inittab.5
Normal file
265
man/inittab.5
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.\"{{{}}}
|
||||||
|
.\"{{{ Title
|
||||||
|
.TH INITTAB 5 "Dec 4, 2001" "" "Linux System Administrator's Manual"
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Name
|
||||||
|
.SH NAME
|
||||||
|
inittab \- format of the inittab file used by the sysv-compatible init
|
||||||
|
process
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Description
|
||||||
|
.SH DESCRIPTION
|
||||||
|
The \fBinittab\fP file describes which processes are started at bootup and
|
||||||
|
during normal operation (e.g.\& /etc/init.d/boot, /etc/init.d/rc, gettys...).
|
||||||
|
.BR Init (8)
|
||||||
|
distinguishes multiple \fIrunlevels\fP, each of which can have its own set of
|
||||||
|
processes that are started. Valid runlevels are \fB0\fP\-\fB6\fP plus
|
||||||
|
\fBA\fP, \fBB\fP, and \fBC\fP for \fBondemand\fP entries. An entry in the
|
||||||
|
\fBinittab\fP file has the following format:
|
||||||
|
.RS
|
||||||
|
.sp
|
||||||
|
\fIid\fP:\fIrunlevels\fP:\fIaction\fP:\fIprocess\fP
|
||||||
|
.sp
|
||||||
|
.RE
|
||||||
|
Lines beginning with `#' are ignored.
|
||||||
|
.\"{{{ id
|
||||||
|
.IP \fIid\fP
|
||||||
|
is a unique sequence of 1-4 characters which identifies an entry in
|
||||||
|
.B inittab
|
||||||
|
(for versions of sysvinit compiled with the \fIold\fP libc5 (< 5.2.18) or
|
||||||
|
a.out libraries the limit is 2 characters).
|
||||||
|
.sp
|
||||||
|
Note: traditionally, for getty and other login processes, the value of the
|
||||||
|
\fIid\fP field is kept the same as the suffix of the corresponding tty, e.g.\&
|
||||||
|
\fB1\fP for \fBtty1\fP. Some ancient login accounting programs might
|
||||||
|
expect this, though I can't think of any.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ runlevels
|
||||||
|
.IP \fIrunlevels\fP
|
||||||
|
lists the runlevels for which the specified action should be taken.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ action
|
||||||
|
.IP \fIaction\fP
|
||||||
|
describes which action should be taken.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ process
|
||||||
|
.IP \fIprocess\fP
|
||||||
|
specifies the process to be executed. If the process field starts with
|
||||||
|
a `+' character,
|
||||||
|
.B init
|
||||||
|
will not do utmp and wtmp accounting for that process. This is needed for
|
||||||
|
gettys that insist on doing their own utmp/wtmp housekeeping. This is also
|
||||||
|
a historic bug.
|
||||||
|
.\"}}}
|
||||||
|
.PP
|
||||||
|
The \fIrunlevels\fP field may contain multiple characters for different
|
||||||
|
runlevels. For example, \fB123\fP specifies that the process should be
|
||||||
|
started in runlevels 1, 2, and 3.
|
||||||
|
The \fIrunlevels\fP for \fBondemand\fP entries may contain an \fBA\fP,
|
||||||
|
\fBB\fP, or \fBC\fP. The \fIrunlevels\fP field of \fBsysinit\fP,
|
||||||
|
\fBboot\fP, and \fBbootwait\fP entries are ignored.
|
||||||
|
.PP
|
||||||
|
When the system runlevel is changed, any running processes that are not
|
||||||
|
specified for the new runlevel are killed, first with \s-2SIGTERM\s0,
|
||||||
|
then with \s-2SIGKILL\s0.
|
||||||
|
.PP
|
||||||
|
Valid actions for the \fIaction\fP field are:
|
||||||
|
.\"{{{ respawn
|
||||||
|
.IP \fBrespawn\fP
|
||||||
|
The process will be restarted whenever it terminates (e.g.\& getty).
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ wait
|
||||||
|
.IP \fBwait\fP
|
||||||
|
The process will be started once when the specified runlevel is entered and
|
||||||
|
.B init
|
||||||
|
will wait for its termination.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ once
|
||||||
|
.IP \fBonce\fP
|
||||||
|
The process will be executed once when the specified runlevel is
|
||||||
|
entered.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ boot
|
||||||
|
.IP \fBboot\fP
|
||||||
|
The process will be executed during system boot. The \fIrunlevels\fP
|
||||||
|
field is ignored.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ bootwait
|
||||||
|
.IP \fBbootwait\fP
|
||||||
|
The process will be executed during system boot, while
|
||||||
|
.B init
|
||||||
|
waits for its termination (e.g.\& /etc/rc).
|
||||||
|
The \fIrunlevels\fP field is ignored.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ off
|
||||||
|
.IP \fBoff\fP
|
||||||
|
This does nothing.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ ondemand
|
||||||
|
.IP \fBondemand\fP
|
||||||
|
A process marked with an \fBondemand\fP runlevel will be executed
|
||||||
|
whenever the specified \fBondemand\fP runlevel is called. However, no
|
||||||
|
runlevel change will occur (\fBondemand\fP runlevels are `a', `b',
|
||||||
|
and `c').
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ initdefault
|
||||||
|
.IP \fBinitdefault\fP
|
||||||
|
An \fBinitdefault\fP entry specifies the runlevel which should be
|
||||||
|
entered after system boot. If none exists,
|
||||||
|
.B init
|
||||||
|
will ask for a runlevel on the console. The \fIprocess\fP field is ignored.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ sysinit
|
||||||
|
.IP \fBsysinit\fP
|
||||||
|
The process will be executed during system boot. It will be
|
||||||
|
executed before any \fBboot\fP or \fB bootwait\fP entries.
|
||||||
|
The \fIrunlevels\fP field is ignored.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ powerwait
|
||||||
|
.IP \fBpowerwait\fP
|
||||||
|
The process will be executed when the power goes down. Init is usually
|
||||||
|
informed about this by a process talking to a UPS connected to the computer.
|
||||||
|
\fBInit\fP will wait for the process to finish before continuing.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ powerfail
|
||||||
|
.IP \fBpowerfail\fP
|
||||||
|
As for \fBpowerwait\fP, except that \fBinit\fP does not wait for the process's
|
||||||
|
completion.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ powerokwait
|
||||||
|
.IP \fBpowerokwait\fP
|
||||||
|
This process will be executed as soon as \fBinit\fP is informed that the
|
||||||
|
power has been restored.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ powerfailnow
|
||||||
|
.IP \fBpowerfailnow\fP
|
||||||
|
This process will be executed when \fBinit\fP is told that the battery of
|
||||||
|
the external UPS is almost empty and the power is failing (provided that the
|
||||||
|
external UPS and the monitoring process are able to detect this condition).
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ ctrlaltdel
|
||||||
|
.IP \fBctrlaltdel\fP
|
||||||
|
The process will be executed when \fBinit\fP receives the SIGINT signal.
|
||||||
|
This means that someone on the system console has pressed the
|
||||||
|
\fBCTRL\-ALT\-DEL\fP key combination. Typically one wants to execute some
|
||||||
|
sort of \fBshutdown\fP either to get into single\-user level or to
|
||||||
|
reboot the machine.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ kbrequest
|
||||||
|
.IP \fBkbrequest\fP
|
||||||
|
The process will be executed when \fBinit\fP receives a signal from the
|
||||||
|
keyboard handler that a special key combination was pressed on the
|
||||||
|
console keyboard.
|
||||||
|
.sp
|
||||||
|
The documentation for this function is not complete yet; more documentation
|
||||||
|
can be found in the kbd-x.xx packages (most recent was kbd-0.94 at
|
||||||
|
the time of this writing). Basically you want to map some keyboard
|
||||||
|
combination to the "KeyboardSignal" action. For example, to map Alt-Uparrow
|
||||||
|
for this purpose use the following in your keymaps file:
|
||||||
|
.RS
|
||||||
|
.sp
|
||||||
|
alt keycode 103 = KeyboardSignal
|
||||||
|
.sp
|
||||||
|
.RE
|
||||||
|
.\"}}}
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Examples
|
||||||
|
.SH EXAMPLES
|
||||||
|
This is an example of a inittab which resembles the old Linux inittab:
|
||||||
|
.RS
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ne 7
|
||||||
|
# inittab for linux
|
||||||
|
id:1:initdefault:
|
||||||
|
rc::bootwait:/etc/rc
|
||||||
|
1:1:respawn:/etc/getty 9600 tty1
|
||||||
|
2:1:respawn:/etc/getty 9600 tty2
|
||||||
|
3:1:respawn:/etc/getty 9600 tty3
|
||||||
|
4:1:respawn:/etc/getty 9600 tty4
|
||||||
|
.fi
|
||||||
|
.sp
|
||||||
|
.RE
|
||||||
|
This inittab file executes \fB/etc/rc\fP during boot and starts gettys
|
||||||
|
on tty1\-tty4.
|
||||||
|
.PP
|
||||||
|
A more elaborate \fBinittab\fP with different runlevels (see the comments
|
||||||
|
inside):
|
||||||
|
.RS
|
||||||
|
.sp
|
||||||
|
.nf
|
||||||
|
.ne 19
|
||||||
|
# Level to run in
|
||||||
|
id:2:initdefault:
|
||||||
|
|
||||||
|
# Boot-time system configuration/initialization script.
|
||||||
|
si::sysinit:/etc/init.d/rcS
|
||||||
|
|
||||||
|
# What to do in single-user mode.
|
||||||
|
~:S:wait:/sbin/sulogin
|
||||||
|
|
||||||
|
# /etc/init.d executes the S and K scripts upon change
|
||||||
|
# of runlevel.
|
||||||
|
#
|
||||||
|
# Runlevel 0 is halt.
|
||||||
|
# Runlevel 1 is single-user.
|
||||||
|
# Runlevels 2-5 are multi-user.
|
||||||
|
# Runlevel 6 is reboot.
|
||||||
|
|
||||||
|
l0:0:wait:/etc/init.d/rc 0
|
||||||
|
l1:1:wait:/etc/init.d/rc 1
|
||||||
|
l2:2:wait:/etc/init.d/rc 2
|
||||||
|
l3:3:wait:/etc/init.d/rc 3
|
||||||
|
l4:4:wait:/etc/init.d/rc 4
|
||||||
|
l5:5:wait:/etc/init.d/rc 5
|
||||||
|
l6:6:wait:/etc/init.d/rc 6
|
||||||
|
|
||||||
|
# What to do at the "3 finger salute".
|
||||||
|
ca::ctrlaltdel:/sbin/shutdown -t1 -h now
|
||||||
|
|
||||||
|
# Runlevel 2,3: getty on virtual consoles
|
||||||
|
# Runlevel 3: getty on terminal (ttyS0) and modem (ttyS1)
|
||||||
|
1:23:respawn:/sbin/getty tty1 VC linux
|
||||||
|
2:23:respawn:/sbin/getty tty2 VC linux
|
||||||
|
3:23:respawn:/sbin/getty tty3 VC linux
|
||||||
|
4:23:respawn:/sbin/getty tty4 VC linux
|
||||||
|
S0:3:respawn:/sbin/getty -L 9600 ttyS0 vt320
|
||||||
|
S1:3:respawn:/sbin/mgetty -x0 -D ttyS1
|
||||||
|
|
||||||
|
.fi
|
||||||
|
.sp
|
||||||
|
.RE
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Files
|
||||||
|
.SH FILES
|
||||||
|
/etc/inittab
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Author
|
||||||
|
.SH AUTHOR
|
||||||
|
\fBInit\fP was written by Miquel van Smoorenburg
|
||||||
|
(miquels@cistron.nl). This manual page was written by
|
||||||
|
Sebastian Lederer (lederer@francium.informatik.uni-bonn.de) and modified
|
||||||
|
by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ See also
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR init (8),
|
||||||
|
.BR telinit (8)
|
||||||
|
.\"}}}
|
49
man/killall5.8
Normal file
49
man/killall5.8
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH KILLALL5 8 "04 Nov 2003" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
killall5 -- send a signal to all processes.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B killall5
|
||||||
|
.RB -signalnumber
|
||||||
|
.RB [ \-o
|
||||||
|
.IR omitpid ]
|
||||||
|
.RB [ \-o
|
||||||
|
.IR omitpid.. ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B killall5
|
||||||
|
is the SystemV killall command. It sends a signal to all processes except
|
||||||
|
kernel threads and the processes in its own session, so it won't kill
|
||||||
|
the shell that is running the script it was called from. Its primary
|
||||||
|
(only) use is in the \fBrc\fP scripts found in the /etc/init.d directory.
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP "-o \fIomitpid\fP"
|
||||||
|
Tells \fIkillall5\fP to omit processes with that process id.
|
||||||
|
.SH NOTES
|
||||||
|
\fIkillall5\fP can also be invoked as pidof, which is simply a
|
||||||
|
(symbolic) link to the \fIkillall5\fP program.
|
||||||
|
.SH EXIT STATUS
|
||||||
|
The program return zero if it killed processes. It return 2 if no
|
||||||
|
process were killed, and 1 if it was unable to find any processes
|
||||||
|
(/proc/ is missing).
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR halt (8),
|
||||||
|
.BR reboot (8),
|
||||||
|
.BR pidof (8)
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
122
man/last.1
Normal file
122
man/last.1
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.\"{{{}}}
|
||||||
|
.\"{{{ Title
|
||||||
|
.TH LAST,LASTB 1 "Jul 31, 2004" "" "Linux System Administrator's Manual"
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Name
|
||||||
|
.SH NAME
|
||||||
|
last, lastb \- show listing of last logged in users
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Synopsis
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B last
|
||||||
|
.RB [ \-R ]
|
||||||
|
.RB [ \-\fInum\fP ]
|
||||||
|
.RB "[ \-\fBn\fP \fInum\fP ]"
|
||||||
|
.RB [ \-adFiox ]
|
||||||
|
.RB "[ \-\fBf\fP \fIfile\fP ]"
|
||||||
|
.RB "[ \-\fBt\fP \fIYYYYMMDDHHMMSS\fP ]"
|
||||||
|
.RI [ name... ]
|
||||||
|
.RI [ tty... ]
|
||||||
|
.br
|
||||||
|
.B lastb
|
||||||
|
.RB [ \-R ]
|
||||||
|
.RB [ \-\fInum\fP ]
|
||||||
|
.RB "[ \-\fBn\fP \fInum\fP ]"
|
||||||
|
.RB "[ \-\fBf\fP \fIfile\fP ]"
|
||||||
|
.RB [ \-adFiox ]
|
||||||
|
.RI [ name... ]
|
||||||
|
.RI [ tty... ]
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Description
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Last
|
||||||
|
searches back through the file \fB/var/log/wtmp\fP (or the file
|
||||||
|
designated by the \fB\-f\fP flag) and displays a list of all
|
||||||
|
users logged in (and out) since that file was created. Names of users
|
||||||
|
and tty's can be given, in which case \fBlast\fP will show only those entries
|
||||||
|
matching the arguments. Names of ttys can be abbreviated, thus \fBlast
|
||||||
|
0\fP is the same as \fBlast tty0\fP.
|
||||||
|
.PP
|
||||||
|
When \fBlast\fP catches a \s-2SIGINT\s0 signal (generated by the interrupt key,
|
||||||
|
usually control-C) or a \s-2SIGQUIT\s0 signal (generated by the quit key,
|
||||||
|
usually control-\e), \fBlast\fP will show how far it has searched through the
|
||||||
|
file; in the case of the \s-2SIGINT\s0 signal \fBlast\fP will then terminate.
|
||||||
|
.PP
|
||||||
|
The pseudo user \fBreboot\fP logs in each time the system is rebooted.
|
||||||
|
Thus \fBlast reboot\fP will show a log of all reboots since the log file
|
||||||
|
was created.
|
||||||
|
.PP
|
||||||
|
\fBLastb\fP is the same as \fBlast\fP, except that by default it shows a log
|
||||||
|
of the file \fB/var/log/btmp\fP, which contains all the bad login attempts.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Options
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP "\fB\-f\fP \fIfile\fP"
|
||||||
|
Tells \fBlast\fP to use a specific file instead of \fB/var/log/wtmp\fP.
|
||||||
|
.IP \fB\-\fP\fInum\fP
|
||||||
|
This is a count telling \fBlast\fP how many lines to show.
|
||||||
|
.IP "\fB\-n\fP \fInum\fP"
|
||||||
|
The same.
|
||||||
|
.IP "\fB\-t\fP \fIYYYYMMDDHHMMSS\fP"
|
||||||
|
Display the state of logins as of the specified time. This is
|
||||||
|
useful, e.g., to determine easily who was logged in at a particular
|
||||||
|
time -- specify that time with \fB\-t\fP and look for "still logged
|
||||||
|
in".
|
||||||
|
.IP \fB\-R\fP
|
||||||
|
Suppresses the display of the hostname field.
|
||||||
|
.IP \fB\-a\fP
|
||||||
|
Display the hostname in the last column. Useful in combination
|
||||||
|
with the next flag.
|
||||||
|
.IP \fB\-d\fP
|
||||||
|
For non-local logins, Linux stores not only the host name of the remote
|
||||||
|
host but its IP number as well. This option translates the IP number
|
||||||
|
back into a hostname.
|
||||||
|
.IP \fB\-F\fP
|
||||||
|
Print full login and logout times and dates.
|
||||||
|
.IP \fB\-i\fP
|
||||||
|
This option is like \fB-d\fP in that it displays the IP number of the remote
|
||||||
|
host, but it displays the IP number in numbers-and-dots notation.
|
||||||
|
.IP \fB\-o\fP
|
||||||
|
Read an old-type wtmp file (written by linux-libc5 applications).
|
||||||
|
.IP \fB\-x\fP
|
||||||
|
Display the system shutdown entries and run level changes.
|
||||||
|
.\"}}}
|
||||||
|
.SH NOTES
|
||||||
|
The files \fIwtmp\fP and \fIbtmp\fP might not be found. The system only
|
||||||
|
logs information in these files if they are present. This is a local
|
||||||
|
configuration issue. If you want the files to be used, they can be
|
||||||
|
created with a simple \fBtouch\fP(1) command (for example,
|
||||||
|
\fItouch /var/log/wtmp\fP).
|
||||||
|
.\"{{{ Files
|
||||||
|
.SH FILES
|
||||||
|
/var/log/wtmp
|
||||||
|
.br
|
||||||
|
/var/log/btmp
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Author
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ See also
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR shutdown (8),
|
||||||
|
.BR login (1),
|
||||||
|
.BR init (8)
|
||||||
|
.\"}}}
|
1
man/lastb.1
Normal file
1
man/lastb.1
Normal file
@ -0,0 +1 @@
|
|||||||
|
.so man1/last.1
|
61
man/mesg.1
Normal file
61
man/mesg.1
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.\"{{{}}}
|
||||||
|
.\"{{{ Title
|
||||||
|
.TH MESG 1 "Feb 26, 2001" "" "Linux User's Manual"
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Name
|
||||||
|
.SH NAME
|
||||||
|
mesg \- control write access to your terminal
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Synopsis
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B mesg
|
||||||
|
.RB [ y | n ]
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Description
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Mesg
|
||||||
|
controls the access to your terminal by others. It's typically used to
|
||||||
|
allow or disallow other users to write to your terminal (see \fBwrite\fP(1)).
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Options
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP \fBy\fP
|
||||||
|
Allow write access to your terminal.
|
||||||
|
.IP \fBn\fP
|
||||||
|
Disallow write access to your terminal.
|
||||||
|
.PP
|
||||||
|
If no option is given, \fBmesg\fP prints out the current access state of your
|
||||||
|
terminal.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Notes
|
||||||
|
.SH NOTES
|
||||||
|
\fBMesg\fP assumes that its standard input is connected to your
|
||||||
|
terminal. That also means that if you are logged in multiple times,
|
||||||
|
you can get/set the mesg status of other sessions by using redirection.
|
||||||
|
For example "mesg n < /dev/pts/46".
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg (miquels@cistron.nl)
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ See also
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR talk (1),
|
||||||
|
.BR write (1),
|
||||||
|
.BR wall (1)
|
||||||
|
.\"}}}
|
54
man/mountpoint.1
Normal file
54
man/mountpoint.1
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH MOUNTPOINT 1 "Mar 15, 2004" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
mountpoint \- see if a directory is a mountpoint
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /bin/mountpoint
|
||||||
|
.RB [ \-q ]
|
||||||
|
.RB [ \-d ]
|
||||||
|
.I /path/to/directory
|
||||||
|
.br
|
||||||
|
.B /bin/mountpoint
|
||||||
|
.RB \-x
|
||||||
|
.I /dev/device
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBMountpoint\fP checks if the directory is a mountpoint.
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP \fB\-q\fP
|
||||||
|
Be quiet - don't print anything.
|
||||||
|
.IP \fB\-d\fP
|
||||||
|
Print major/minor device number of the filesystem on stdout.
|
||||||
|
.IP \fB\-x\fP
|
||||||
|
Print major/minor device number of the blockdevice on stdout.
|
||||||
|
.SH EXIT STATUS
|
||||||
|
Zero if the directory is a mountpoint, non-zero if not.
|
||||||
|
.SH NOTES
|
||||||
|
Symbolic links are not followed, except when the \fB-x\fP option is
|
||||||
|
used. To force following symlinks, add a trailing slash to the
|
||||||
|
path of the directory.
|
||||||
|
.PP
|
||||||
|
The name of the command is misleading when the -x option is used,
|
||||||
|
but the option is useful for comparing if a directory and a device
|
||||||
|
match up, and there is no other command that can print the info easily.
|
||||||
|
.PP
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR stat (1)
|
78
man/pidof.8
Normal file
78
man/pidof.8
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH PIDOF 8 "01 Sep 1998" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
pidof -- find the process ID of a running program.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B pidof
|
||||||
|
.RB [ \-s ]
|
||||||
|
.RB [ \-c ]
|
||||||
|
.RB [ \-x ]
|
||||||
|
.RB [ \-o
|
||||||
|
.IR omitpid ]
|
||||||
|
.RB [ \-o
|
||||||
|
.IR omitpid.. ]
|
||||||
|
.B program
|
||||||
|
.RB [ program.. ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Pidof
|
||||||
|
finds the process id's (pids) of the named programs. It prints those
|
||||||
|
id's on the standard output. This program is on some systems used in
|
||||||
|
run-level change scripts, especially when the system has a
|
||||||
|
\fISystem-V\fP like \fIrc\fP structure. In that case these scripts are
|
||||||
|
located in /etc/rc?.d, where ? is the runlevel. If the system has
|
||||||
|
a
|
||||||
|
.B start-stop-daemon
|
||||||
|
(8) program that should be used instead.
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP -s
|
||||||
|
Single shot - this instructs the program to only return one \fIpid\fP.
|
||||||
|
.IP -c
|
||||||
|
Only return process ids that are running with the same root directory.
|
||||||
|
This option is ignored for non-root users, as they will be unable to check
|
||||||
|
the current root directory of processes they do not own.
|
||||||
|
.IP -x
|
||||||
|
Scripts too - this causes the program to also return process id's of
|
||||||
|
shells running the named scripts.
|
||||||
|
.IP "-o \fIomitpid\fP"
|
||||||
|
Tells \fIpidof\fP to omit processes with that process id. The special
|
||||||
|
pid \fB%PPID\fP can be used to name the parent process of the \fIpidof\fP
|
||||||
|
program, in other words the calling shell or shell script.
|
||||||
|
.SH "EXIT STATUS"
|
||||||
|
.TP
|
||||||
|
.B 0
|
||||||
|
At least one program was found with the requested name.
|
||||||
|
.TP
|
||||||
|
.B 1
|
||||||
|
No program was found with the requested name.
|
||||||
|
.SH NOTES
|
||||||
|
\fIpidof\fP is actually the same program as \fIkillall5\fP;
|
||||||
|
the program behaves according to the name under which it is called.
|
||||||
|
.PP
|
||||||
|
When \fIpidof\fP is invoked with a full pathname to the program it
|
||||||
|
should find the pid of, it is reasonably safe. Otherwise it is possible
|
||||||
|
that it returns pids of running programs that happen to have the same name
|
||||||
|
as the program you're after but are actually other programs.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR shutdown (8),
|
||||||
|
.BR init (8),
|
||||||
|
.BR halt (8),
|
||||||
|
.BR reboot (8),
|
||||||
|
.BR killall5 (8)
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
1
man/poweroff.8
Normal file
1
man/poweroff.8
Normal file
@ -0,0 +1 @@
|
|||||||
|
.so man8/halt.8
|
1
man/reboot.8
Normal file
1
man/reboot.8
Normal file
@ -0,0 +1 @@
|
|||||||
|
.so man8/halt.8
|
56
man/runlevel.8
Normal file
56
man/runlevel.8
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1997 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH RUNLEVEL 8 "May 27, 1997" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
runlevel -- find the previous and current system runlevel.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B runlevel
|
||||||
|
.RI [ utmp ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Runlevel
|
||||||
|
reads the system
|
||||||
|
.I utmp
|
||||||
|
file (typically
|
||||||
|
.IR /var/run/utmp )
|
||||||
|
to locate the runlevel record, and then
|
||||||
|
prints the previous and current system runlevel on its standard output,
|
||||||
|
separated by a single space. If there is no previous system
|
||||||
|
runlevel, the letter \fBN\fP will be printed instead.
|
||||||
|
.PP
|
||||||
|
If no
|
||||||
|
.I utmp
|
||||||
|
file exists, or if no runlevel record can be found,
|
||||||
|
.B runlevel
|
||||||
|
prints the word \fBunknown\fP and exits with an error.
|
||||||
|
.PP
|
||||||
|
.B Runlevel
|
||||||
|
can be used in \fIrc\fP scripts as a substitute for the System-V
|
||||||
|
\fBwho -r\fP command.
|
||||||
|
However, in newer versions of \fBinit\fP(8) this information
|
||||||
|
is also available in the environment variables \fBRUNLEVEL\fP and
|
||||||
|
\fBPREVLEVEL\fP.
|
||||||
|
.SH OPTIONS
|
||||||
|
.\"{{{ utmp
|
||||||
|
.IP \fIutmp\fP
|
||||||
|
The name of the \fIutmp\fP file to read.
|
||||||
|
.\"}}}
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR init (8),
|
||||||
|
.BR utmp (5)
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
214
man/shutdown.8
Normal file
214
man/shutdown.8
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.\"{{{}}}
|
||||||
|
.\"{{{ Title
|
||||||
|
.TH SHUTDOWN 8 "November 12, 2003" "" "Linux System Administrator's Manual"
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Name
|
||||||
|
.SH NAME
|
||||||
|
shutdown \- bring the system down
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Synopsis
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /sbin/shutdown
|
||||||
|
.RB [ \-t
|
||||||
|
.IR sec ]
|
||||||
|
.RB [ \-arkhncfFHP ]
|
||||||
|
.I time
|
||||||
|
.RI [ warning-message ]
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Description
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBshutdown\fP brings the system down in a secure way. All logged-in users are
|
||||||
|
notified that the system is going down, and \fBlogin\fP(1) is blocked.
|
||||||
|
It is possible to shut the system down immediately or after a specified delay.
|
||||||
|
All processes are first notified that the system is going down by the
|
||||||
|
signal \s-2SIGTERM\s0. This gives programs like \fBvi\fP(1)
|
||||||
|
the time to save the file being edited,
|
||||||
|
mail and news processing programs a chance to exit cleanly, etc.
|
||||||
|
\fBshutdown\fP does its job by signalling the \fBinit\fP process,
|
||||||
|
asking it to change the runlevel.
|
||||||
|
Runlevel \fB0\fP is used to halt the system, runlevel \fB6\fP is used
|
||||||
|
to reboot the system, and runlevel \fB1\fP is used to put to system into
|
||||||
|
a state where administrative tasks can be performed; this is the default
|
||||||
|
if neither the \fI-h\fP or \fI-r\fP flag is given to \fBshutdown\fP.
|
||||||
|
To see which actions are taken on halt or reboot see the appropriate
|
||||||
|
entries for these runlevels in the file \fI/etc/inittab\fP.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Options
|
||||||
|
.SH OPTIONS
|
||||||
|
.\"{{{ -a
|
||||||
|
.IP "\fB\-a\fP
|
||||||
|
Use \fB/etc/shutdown.allow\fP.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -t sec
|
||||||
|
.IP "\fB\-t\fP \fIsec\fP"
|
||||||
|
Tell \fBinit\fP(8) to wait \fIsec\fP seconds between sending processes the
|
||||||
|
warning and the kill signal, before changing to another runlevel.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -k
|
||||||
|
.IP \fB\-k\fP
|
||||||
|
Don't really shutdown; only send the warning messages to everybody.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -r
|
||||||
|
.IP \fB\-r\fP
|
||||||
|
Reboot after shutdown.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -h
|
||||||
|
.IP \fB\-h\fP
|
||||||
|
Halt or power off after shutdown.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -H
|
||||||
|
.IP \fB\-H\fP
|
||||||
|
Modifier to the -h flag. Halt action is to halt or drop into boot
|
||||||
|
monitor on systems that support it. Must be used with the -h flag.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -P
|
||||||
|
.IP \fB\-P\fP
|
||||||
|
Halt action is to turn off the power.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -n
|
||||||
|
.IP \fB\-n\fP
|
||||||
|
[DEPRECATED] Don't call \fBinit\fP(8) to do the shutdown but do it ourself.
|
||||||
|
The use of this option is discouraged, and its results are not always what
|
||||||
|
you'd expect.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -f
|
||||||
|
.IP \fB\-f\fP
|
||||||
|
Skip fsck on reboot.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -F
|
||||||
|
.IP \fB\-F\fP
|
||||||
|
Force fsck on reboot.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ -c
|
||||||
|
.IP \fB\-c\fP
|
||||||
|
Cancel an already running shutdown. With this option it is of course
|
||||||
|
not possible to give the \fBtime\fP argument, but you can enter a
|
||||||
|
explanatory message on the command line that will be sent to all users.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ time
|
||||||
|
.IP \fItime\fP
|
||||||
|
When to shutdown.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ warning-message
|
||||||
|
.IP \fIwarning-message\fP
|
||||||
|
Message to send to all users.
|
||||||
|
.\"}}}
|
||||||
|
.PP
|
||||||
|
The \fItime\fP argument can have different formats. First, it can be an
|
||||||
|
absolute time in the format \fIhh:mm\fP, in which \fIhh\fP is the hour
|
||||||
|
(1 or 2 digits) and \fImm\fP is the minute of the hour (in two digits).
|
||||||
|
Second, it can be in the format \fB+\fP\fIm\fP, in which \fIm\fP is the
|
||||||
|
number of minutes to wait. The word \fBnow\fP is an alias for \fB+0\fP.
|
||||||
|
.PP
|
||||||
|
If shutdown is called with a delay, it will create the advisory file
|
||||||
|
.I /etc/nologin
|
||||||
|
which causes programs such as \fIlogin(1)\fP to not allow new user
|
||||||
|
logins. This file is created five minutes before the shutdown sequence
|
||||||
|
starts. Shutdown removes this file if it is stopped before it
|
||||||
|
can signal init (i.e. it is cancelled or something goes wrong).
|
||||||
|
It also removes it before calling init to change the runlevel.
|
||||||
|
.PP
|
||||||
|
The \fB\-f\fP flag means `reboot fast'. This only creates an advisory
|
||||||
|
file \fI/fastboot\fP which can be tested by the system when it comes
|
||||||
|
up again. The boot rc file can test if this file is present, and decide not
|
||||||
|
to run \fBfsck\fP(1) since the system has been shut down in the proper way.
|
||||||
|
After that, the boot process should remove \fI/fastboot\fP.
|
||||||
|
.PP
|
||||||
|
The \fB\-F\fP flag means `force fsck'. This only creates an advisory
|
||||||
|
file \fI/forcefsck\fP which can be tested by the system when it comes
|
||||||
|
up again. The boot rc file can test if this file is present, and decide
|
||||||
|
to run \fBfsck\fP(1) with a special `force' flag so that even properly
|
||||||
|
unmounted file systems get checked.
|
||||||
|
After that, the boot process should remove \fI/forcefsck\fP.
|
||||||
|
.PP
|
||||||
|
The \fB-n\fP flag causes \fBshutdown\fP not to call \fBinit\fP,
|
||||||
|
but to kill all running processes itself.
|
||||||
|
\fBshutdown\fP will then turn off quota, accounting, and swapping
|
||||||
|
and unmount all file systems.
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ Files
|
||||||
|
.SH ACCESS CONTROL
|
||||||
|
\fBshutdown\fP can be called from \fBinit\fP(8) when the magic keys
|
||||||
|
\fBCTRL-ALT-DEL\fP are pressed, by creating an appropriate entry in
|
||||||
|
\fI/etc/inittab\fP. This means that everyone who has physical access
|
||||||
|
to the console keyboard can shut the system down. To prevent this,
|
||||||
|
\fBshutdown\fP can check to see if an authorized user is logged in on
|
||||||
|
one of the virtual consoles. If \fBshutdown\fP is called with the \fB-a\fP
|
||||||
|
argument (add this to the invocation of shutdown in /etc/inittab),
|
||||||
|
it checks to see if the file \fI/etc/shutdown.allow\fP is present.
|
||||||
|
It then compares the login names in that file with the list of people
|
||||||
|
that are logged in on a virtual console (from \fI/var/run/utmp\fP). Only
|
||||||
|
if one of those authorized users \fBor root\fP is logged in, it will
|
||||||
|
proceed. Otherwise it will write the message
|
||||||
|
.sp 1
|
||||||
|
.nf
|
||||||
|
\fBshutdown: no authorized users logged in\fP
|
||||||
|
.fi
|
||||||
|
.sp 1
|
||||||
|
to the (physical) system console. The format of \fI/etc/shutdown.allow\fP
|
||||||
|
is one user name per line. Empty lines and comment lines (prefixed by a
|
||||||
|
\fB#\fP) are allowed. Currently there is a limit of 32 users in this file.
|
||||||
|
.sp 1
|
||||||
|
Note that if \fI/etc/shutdown.allow\fP is not present, the \fB-a\fP
|
||||||
|
argument is ignored.
|
||||||
|
.SH HALT OR POWEROFF
|
||||||
|
The \fB-H\fP option just sets the \fIinit\fP environment variable
|
||||||
|
\fIINIT_HALT\fP to \fIHALT\fP, and the \fB-P\fP option just sets
|
||||||
|
that variable to \fIPOWEROFF\fP. The shutdown script that calls
|
||||||
|
\fBhalt\fP(8) as the last thing in the shutdown sequence should
|
||||||
|
check these environment variables and call \fBhalt\fP(8) with
|
||||||
|
the right options for these options to actually have any effect.
|
||||||
|
Debian 3.1 (sarge) supports this.
|
||||||
|
.SH FILES
|
||||||
|
.nf
|
||||||
|
/fastboot
|
||||||
|
/etc/inittab
|
||||||
|
/etc/init.d/halt
|
||||||
|
/etc/init.d/reboot
|
||||||
|
/etc/shutdown.allow
|
||||||
|
.fi
|
||||||
|
.\"}}}
|
||||||
|
.SH NOTES
|
||||||
|
A lot of users forget to give the \fItime\fP argument
|
||||||
|
and are then puzzled by the error message \fBshutdown\fP produces. The
|
||||||
|
\fItime\fP argument is mandatory; in 90 percent of all cases this argument
|
||||||
|
will be the word \fBnow\fP.
|
||||||
|
.PP
|
||||||
|
Init can only capture CTRL-ALT-DEL and start shutdown in console mode.
|
||||||
|
If the system is running the X window System, the X server processes
|
||||||
|
all key strokes. Some X11 environments make it possible to capture
|
||||||
|
CTRL-ALT-DEL, but what exactly is done with that event depends on
|
||||||
|
that environment.
|
||||||
|
.PP
|
||||||
|
Shutdown wasn't designed to be run setuid. /etc/shutdown.allow is
|
||||||
|
not used to find out who is executing shutdown, it ONLY checks who
|
||||||
|
is currently logged in on (one of the) console(s).
|
||||||
|
.\"{{{ Author
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
.\"}}}
|
||||||
|
.\"{{{ See also
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR fsck (8),
|
||||||
|
.BR init (8),
|
||||||
|
.BR halt (8),
|
||||||
|
.BR poweroff (8),
|
||||||
|
.BR reboot (8)
|
||||||
|
.\"}}}
|
87
man/sulogin.8
Normal file
87
man/sulogin.8
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2006 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH SULOGIN 8 "17 Jan 2006" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
sulogin \- Single-user login
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B sulogin
|
||||||
|
[ \fB\-e\fP ]
|
||||||
|
[ \fB\-p\fP ]
|
||||||
|
[ \fB\-t\fP \fISECONDS\fP ]
|
||||||
|
[ \fITTY\fP ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.I sulogin
|
||||||
|
is invoked by \fBinit(8)\fP when the system goes into single user mode.
|
||||||
|
(This is done through an entry in \fIinittab(5)\fP.)
|
||||||
|
\fBInit\fP also
|
||||||
|
tries to execute \fIsulogin\fP when
|
||||||
|
the boot loader (e.g., \fBgrub\fP(8))
|
||||||
|
passes it the \fB\-b\fP option.
|
||||||
|
.PP
|
||||||
|
The user is prompted
|
||||||
|
.IP "" .5i
|
||||||
|
Give root password for system maintenance
|
||||||
|
.br
|
||||||
|
(or type Control\-D for normal startup):
|
||||||
|
.PP
|
||||||
|
\fIsulogin\fP will be connected to the current terminal, or to the
|
||||||
|
optional device that can be specified on the command line
|
||||||
|
(typically \fB/dev/console\fP).
|
||||||
|
.PP
|
||||||
|
If the \fB\-t\fP option is used then the program only waits
|
||||||
|
the given number of seconds for user input.
|
||||||
|
.PP
|
||||||
|
If the \fB\-p\fP option is used then the single-user shell is invoked
|
||||||
|
with a \fIdash\fP as the first character in \fIargv[0]\fP.
|
||||||
|
This causes the shell process to behave as a login shell.
|
||||||
|
The default is \fInot\fP to do this,
|
||||||
|
so that the shell will \fInot\fP read \fB/etc/profile\fP
|
||||||
|
or \fB$HOME/.profile\fP at startup.
|
||||||
|
.PP
|
||||||
|
After the user exits the single-user shell,
|
||||||
|
or presses control\-D at the prompt,
|
||||||
|
the system will (continue to) boot to the default runlevel.
|
||||||
|
.SH ENVIRONMENT VARIABLES
|
||||||
|
\fIsulogin\fP looks for the environment variable \fBSUSHELL\fP or
|
||||||
|
\fBsushell\fP to determine what shell to start. If the environment variable
|
||||||
|
is not set, it will try to execute root's shell from /etc/passwd. If that
|
||||||
|
fails it will fall back to \fB/bin/sh\fP.
|
||||||
|
.PP
|
||||||
|
This is very valuable together with the \fB\-b\fP option to init. To boot
|
||||||
|
the system into single user mode, with the root file system mounted read/write,
|
||||||
|
using a special "fail safe" shell that is statically linked (this example
|
||||||
|
is valid for the LILO bootprompt)
|
||||||
|
.PP
|
||||||
|
boot: linux \-b rw sushell=/sbin/sash
|
||||||
|
.SH FALLBACK METHODS
|
||||||
|
\fIsulogin\fP checks the root password using the standard method (getpwnam)
|
||||||
|
first.
|
||||||
|
Then, if the \fB\-e\fP option was specified,
|
||||||
|
\fIsulogin\fP examines these files directly to find the root password:
|
||||||
|
.PP
|
||||||
|
/etc/passwd,
|
||||||
|
.br
|
||||||
|
/etc/shadow (if present)
|
||||||
|
.PP
|
||||||
|
If they are damaged or nonexistent, sulogin will start a root shell
|
||||||
|
without asking for a password. Only use the \fB\-e\fP option if you
|
||||||
|
are sure the console is physically protected against unauthorized access.
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg <miquels@cistron.nl>
|
||||||
|
.SH SEE ALSO
|
||||||
|
init(8), inittab(5).
|
1
man/telinit.8
Normal file
1
man/telinit.8
Normal file
@ -0,0 +1 @@
|
|||||||
|
.so man8/init.8
|
75
man/wall.1
Normal file
75
man/wall.1
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH WALL 1 "15 April 2003" "" "Linux User's Manual"
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
wall -- send a message to everybody's terminal.
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B wall
|
||||||
|
.RB [ \-n ]
|
||||||
|
.RB [ " message " ]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Wall
|
||||||
|
sends a message to everybody logged in with their
|
||||||
|
.IR mesg (1)
|
||||||
|
permission
|
||||||
|
set to
|
||||||
|
.BR yes .
|
||||||
|
The message can be given as an argument to
|
||||||
|
.IR wall ,
|
||||||
|
or it can be sent to
|
||||||
|
.IR wall 's
|
||||||
|
standard input. When using the standard input from a terminal,
|
||||||
|
the message should be terminated with the
|
||||||
|
.B EOF
|
||||||
|
key (usually Control-D).
|
||||||
|
.PP
|
||||||
|
The length of the message is limited to 20 lines.
|
||||||
|
For every invocation of
|
||||||
|
.I wall
|
||||||
|
a notification will be written to syslog, with facility
|
||||||
|
.B LOG_USER
|
||||||
|
and level
|
||||||
|
.BR LOG_INFO .
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.IP \fB\-n\fn
|
||||||
|
Suppresses the normal banner printed by
|
||||||
|
.IR wall ,
|
||||||
|
changing it to "Remote broadcast message".
|
||||||
|
This option is only available for root if
|
||||||
|
.I wall
|
||||||
|
is installed set-group-id, and is used by
|
||||||
|
.IR rpc.walld (8).
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH ENVIRONMENT
|
||||||
|
.I Wall
|
||||||
|
ignores the
|
||||||
|
.B TZ
|
||||||
|
variable - the time printed in the banner is based on the system's
|
||||||
|
local time.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.IR mesg (1),
|
||||||
|
.IR rpc.rwalld (8).
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
58
obsolete/README.RIGHT.NOW
Normal file
58
obsolete/README.RIGHT.NOW
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
WARNING:
|
||||||
|
|
||||||
|
This version of sysvinit is really different from the 2.50 and
|
||||||
|
earlier version.
|
||||||
|
|
||||||
|
Shutdown now puts the system into runlevel 6 (reboot), 0 (halt)
|
||||||
|
or 1 (single user). This can cause unexpected results if you
|
||||||
|
install the binaries from this release into Slackware distributions
|
||||||
|
older than Slackware 3.0.
|
||||||
|
|
||||||
|
SUPPORTED DISTRIBUTIONS:
|
||||||
|
|
||||||
|
The binaries from this package can be installed in:
|
||||||
|
|
||||||
|
o Debian 1.3 and later
|
||||||
|
o RedHat 3.x and later
|
||||||
|
o Slackware 3.0 (UNTESTED but it might work - no complaints yet).
|
||||||
|
Also read the INIT.README in the slackware/ directory.
|
||||||
|
o Slackware 2.x: see the slackware/ directory
|
||||||
|
|
||||||
|
Do not install any of the scripts from the debian/ directory unless
|
||||||
|
you know what you are doing.
|
||||||
|
|
||||||
|
UNSUPPORTED DISTRIBUTIONS:
|
||||||
|
|
||||||
|
o The rest :)
|
||||||
|
|
||||||
|
If you have a non-supported system, please upgrade to the latest version
|
||||||
|
of your distribution that supports the Linux 2.0.x kernel (probably
|
||||||
|
the reason why you are installing this newer sysvinit).
|
||||||
|
|
||||||
|
You might get away by installing *just* the "init" binary, and nothing
|
||||||
|
else. Do _not_ replace your existing halt, reboot or shutdown programs.
|
||||||
|
|
||||||
|
HOW TO NON DESTRUCTIVELY TEST THE NEW INIT:
|
||||||
|
|
||||||
|
Install *just* the init binary as /sbin/init.new. Now reboot the system,
|
||||||
|
and stop your bootloader so you can give arguments on the command line.
|
||||||
|
With LILO you can usually achieve this by keeping the SHIFT key
|
||||||
|
pressed during boot up. Enter the name of the kernel image (for LILO,
|
||||||
|
TAB shows a list) followed by the argument "init=/sbin/init.new".
|
||||||
|
The name "init.new" is special, do not use something like "init.test".
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
boot: linux init=/sbin/init.new
|
||||||
|
|
||||||
|
YOU CANNOT SHUTDOWN IN A CLEAN WAY AFTER THIS. Your best bet is to use
|
||||||
|
the "-n" flag to shutdown. This is because init is not running as process #1
|
||||||
|
if you use this method. Anyway, if this works, you can remove the old init
|
||||||
|
and copy the new init into place.
|
||||||
|
|
||||||
|
DISCLAIMER:
|
||||||
|
|
||||||
|
If it breaks you get to keep both pieces. If you want to run the latest
|
||||||
|
Linux 2.0.x kernel and you can't get init to work just upgrade your entire
|
||||||
|
distribution to a newer version that supports the 2.0.x kernel properly.
|
||||||
|
|
67
obsolete/bootlogd.init
Executable file
67
obsolete/bootlogd.init
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
#
|
||||||
|
# bootlogd One of the first scripts to be executed. Starts or stops
|
||||||
|
# the bootlogd log program. If this script is called as
|
||||||
|
# "stop-bootlogd", it will stop the daemon instead of
|
||||||
|
# starting it even when called with the "start" argument.
|
||||||
|
#
|
||||||
|
# Version: @(#)bootlogd 2.77 24-Aug-1999 miquels@cistron.nl
|
||||||
|
#
|
||||||
|
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
DAEMON=/sbin/bootlogd
|
||||||
|
NAME=bootlogd
|
||||||
|
DESC="Bootlog daemon"
|
||||||
|
PIDFILE=/var/run/$NAME.pid
|
||||||
|
|
||||||
|
test -f $DAEMON || exit 0
|
||||||
|
|
||||||
|
## set -e # not needed
|
||||||
|
|
||||||
|
. /etc/default/rcS
|
||||||
|
|
||||||
|
case "$0" in
|
||||||
|
*stop-bootlog*)
|
||||||
|
stopper=yes
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start|stop)
|
||||||
|
if [ "$stopper" ] || [ "$1" = "stop" ]
|
||||||
|
then
|
||||||
|
echo -n "Stopping $DESC: "
|
||||||
|
start-stop-daemon --stop --quiet --exec $DAEMON
|
||||||
|
else
|
||||||
|
echo -n "Starting $DESC: "
|
||||||
|
start-stop-daemon --start --quiet --exec $DAEMON -- -r
|
||||||
|
fi
|
||||||
|
if [ "$stopper" ] && [ -f /var/log/boot.log ] && \
|
||||||
|
[ -f /var/log/boot.log~ ]
|
||||||
|
then
|
||||||
|
cd /var/log
|
||||||
|
savelog -p -c 5 boot.log > /dev/null 2>&1
|
||||||
|
mv boot.log.0 boot.log
|
||||||
|
mv boot.log~ boot.log.0
|
||||||
|
fi
|
||||||
|
echo "$NAME."
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
echo -n "Restarting $DESC: "
|
||||||
|
start-stop-daemon --stop --quiet --pidfile \
|
||||||
|
$PIDFILE --exec $DAEMON -- -p $PIDFILE
|
||||||
|
sleep 1
|
||||||
|
start-stop-daemon --start --quiet --pidfile \
|
||||||
|
$PIDFILE --exec $DAEMON -- -p $PIDFILE
|
||||||
|
echo "$NAME."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
N=${0##*/}
|
||||||
|
N=${N#[SK]??}
|
||||||
|
echo "Usage: $N {start|stop|restart|force-reload}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
73
obsolete/powerd.8
Normal file
73
obsolete/powerd.8
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
'\" -*- coding: UTF-8 -*-
|
||||||
|
.\" Copyright (C) 1994 Miquel van Smoorenburg.
|
||||||
|
.\"
|
||||||
|
.\" 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
|
||||||
|
.\"
|
||||||
|
.TH POWERD 8 "Feb 14, 1994" "" "Linux System Administrator's Manual"
|
||||||
|
.SH NAME
|
||||||
|
.\" powerd \(em monitor a serial line connected to an UPS.
|
||||||
|
powerd -- monitor a serial line connected to an UPS.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B /sbin/powerd
|
||||||
|
.RB " serial-device "
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B Powerd
|
||||||
|
is a daemon process that sits in the background and monitors the state
|
||||||
|
of the DCD line of the serial device. This line is meant to be
|
||||||
|
connected to a UPS (Uninterruptible Power Supply) so that \fBpowerd\fP knows
|
||||||
|
about the state of the UPS. As soon as \fBpowerd\fP senses that the
|
||||||
|
power is failing (it sees that DCD goes low) it notifies \fBinit\fP(8),
|
||||||
|
and \fBinit\fP then executes the \fBpowerwait\fP and \fBpowerfail\fP entries.
|
||||||
|
If \fBpowerd\fP senses that the power has been restored, it notifies \fBinit\fP
|
||||||
|
again and \fBinit\fP will execute the \fBpowerokwait\fP entries.
|
||||||
|
.SH ARGUMENTS
|
||||||
|
.IP serial-device
|
||||||
|
Some serial port that is not being used by some other device, and does not
|
||||||
|
share an interrupt with any other serial port.
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
\fBPowerd\fP regularly checks the \fBDSR\fP line to see if it's high.
|
||||||
|
\fBDSR\fP should be directly connected to \fBDTR\fP and \fBpowerd\fP
|
||||||
|
keeps that line high, so if \fBDSR\fP is low then something is wrong
|
||||||
|
with the connection. \fBPowerd\fP will notify you about this fact every
|
||||||
|
two minutes. When it sees that the connection has been restored it
|
||||||
|
will say so.
|
||||||
|
.SH HOWTO
|
||||||
|
It's pretty simple to connect your UPS to the Linux machine. The steps
|
||||||
|
are easy:
|
||||||
|
.TP 0.5i
|
||||||
|
.B 1.
|
||||||
|
Make sure you have an UPS with a simple relay output: it should
|
||||||
|
close its connections (make) if the power is gone, and it should
|
||||||
|
open its connections (break) if the power is good.
|
||||||
|
.TP 0.5i
|
||||||
|
.B 2.
|
||||||
|
Buy a serial plug. Connect the DTR line to the DSR line directly.
|
||||||
|
Connect the DTR line and the DCD line with a \fB10 kilo ohm\fP
|
||||||
|
resistor. Now connect the relay output of the UPS to GROUND
|
||||||
|
and the DCD line. If you don't know what pins DSR, DTR, DCD and
|
||||||
|
GROUND are you can always ask at the store where you bought the plug.
|
||||||
|
.TP 0.5i
|
||||||
|
.B 3.
|
||||||
|
You're all set.
|
||||||
|
.SH BUGS
|
||||||
|
Well, not a real bug but \fBpowerd\fP should be able to do a broadcast or
|
||||||
|
something on the ethernet in case more Linux-boxes are connected to
|
||||||
|
the same UPS and only one of them is connected to the UPS status line.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR shutdown (8),
|
||||||
|
.BR init (8),
|
||||||
|
.BR inittab (5)
|
||||||
|
.SH AUTHOR
|
||||||
|
Miquel van Smoorenburg, miquels@cistron.nl
|
36
obsolete/powerd.README
Normal file
36
obsolete/powerd.README
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
There are 2 *much* better powerd's than the one that is included as
|
||||||
|
an example with sysvinit. The powerd.c in this distribution is just ment
|
||||||
|
as a programming example, not to be used in a real life situation.
|
||||||
|
|
||||||
|
1. GENPOWERD.
|
||||||
|
|
||||||
|
This is a powerd written by Tom Webster <webster@kaiwan.com>. It's a
|
||||||
|
nice package, you can find info at http://www.kaiwan.com/~webster/genpower.html
|
||||||
|
|
||||||
|
2. POWERD-2.0.
|
||||||
|
|
||||||
|
This is another powerd, written by rubini@ipvvis.unipv.it (Alessandro Rubini).
|
||||||
|
The main advantage over genpowerd is that it can signal other machines over
|
||||||
|
the network.
|
||||||
|
|
||||||
|
This LSM may be out of date. Please check if a newer version exists.
|
||||||
|
|
||||||
|
Begin3
|
||||||
|
Title: powerd
|
||||||
|
Version: 2.0
|
||||||
|
Entered-date: Sep 26 1995
|
||||||
|
Description: A daemon to shut down and up computers connected to ups's.
|
||||||
|
Network-aware: server-mode and client-mode allowed.
|
||||||
|
Keywords: ups, powerd, init
|
||||||
|
Author: Alessandro Rubini (based on Miquel van Smoorenburg's work).
|
||||||
|
Maintained-by: rubini@ipvvis.unipv.it (Alessandro Rubini)
|
||||||
|
Primary-site: sunsite.unc.edu /pub/Linux/system/UPS/powerd-2.0.tar.gz
|
||||||
|
25kB powerd-2.0.tar.gz
|
||||||
|
1kB powerd-2.0.lsm
|
||||||
|
Alternate-site:
|
||||||
|
Original-site: iride.unipv.it /pub/linux
|
||||||
|
25kB powerd-2.0.tar.gz
|
||||||
|
1kB powerd-2.0.lsm
|
||||||
|
Platform: Linux. Porting is foreseeable.
|
||||||
|
Copying-policy: GPL
|
||||||
|
End
|
201
obsolete/powerd.c
Normal file
201
obsolete/powerd.c
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* powerd Monitor the DCD line of a serial port connected to
|
||||||
|
* an UPS. If the power goes down, notify init.
|
||||||
|
* If the power comes up again, notify init again.
|
||||||
|
* As long as the power is OK, the DCD line should be
|
||||||
|
* "HIGH". When the power fails, DCD should go "LOW".
|
||||||
|
* Powerd keeps DTR high so that you can connect
|
||||||
|
* DCD and DTR with a resistor of 10 Kilo Ohm and let the
|
||||||
|
* UPS or some relais pull the DCD line to ground.
|
||||||
|
* You also need to connect DTR and DSR together. This
|
||||||
|
* way, powerd can check now and then if DSR is high
|
||||||
|
* so it knows the UPS is connected!!
|
||||||
|
*
|
||||||
|
* Usage: powerd /dev/cua4 (or any other serial device).
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, <miquels@drinkel.cistron.nl>.
|
||||||
|
*
|
||||||
|
* Version: 1.31, 29-Feb-1996.
|
||||||
|
*
|
||||||
|
* This program was originally written for my employer,
|
||||||
|
* ** Cistron Electronics **
|
||||||
|
* who has given kind permission to release this program
|
||||||
|
* for general puppose.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991-1996 Cistron Electronics.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Use the new way of communicating with init. */
|
||||||
|
#define NEWINIT
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "paths.h"
|
||||||
|
#ifdef NEWINIT
|
||||||
|
#include "initreq.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIGPWR
|
||||||
|
# define SIGPWR SIGUSR1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NEWINIT
|
||||||
|
void alrm_handler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tell init the power has either gone or is back. */
|
||||||
|
void powerfail(ok)
|
||||||
|
int ok;
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
#ifdef NEWINIT
|
||||||
|
struct init_request req;
|
||||||
|
|
||||||
|
/* Fill out the request struct. */
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
req.magic = INIT_MAGIC;
|
||||||
|
req.cmd = ok ? INIT_CMD_POWEROK : INIT_CMD_POWERFAIL;
|
||||||
|
|
||||||
|
/* Open the fifo (with timeout) */
|
||||||
|
signal(SIGALRM, alrm_handler);
|
||||||
|
alarm(3);
|
||||||
|
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0
|
||||||
|
&& write(fd, &req, sizeof(req)) == sizeof(req)) {
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Fall through to the old method.. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Create an info file for init. */
|
||||||
|
unlink(PWRSTAT);
|
||||||
|
if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) {
|
||||||
|
if (ok)
|
||||||
|
write(fd, "OK\n", 3);
|
||||||
|
else
|
||||||
|
write(fd, "FAIL\n", 5);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
kill(1, SIGPWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main program. */
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int dtr_bit = TIOCM_DTR;
|
||||||
|
int flags;
|
||||||
|
int status, oldstat = -1;
|
||||||
|
int count = 0;
|
||||||
|
int tries = 0;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "Usage: powerd <device>\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start syslog. */
|
||||||
|
openlog("powerd", LOG_CONS|LOG_PERROR, LOG_DAEMON);
|
||||||
|
|
||||||
|
/* Open monitor device. */
|
||||||
|
if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
|
||||||
|
syslog(LOG_ERR, "%s: %s", argv[1], sys_errlist[errno]);
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Line is opened, so DTR is high. Force it anyway to be sure. */
|
||||||
|
ioctl(fd, TIOCMBIS, &dtr_bit);
|
||||||
|
|
||||||
|
/* Daemonize. */
|
||||||
|
switch(fork()) {
|
||||||
|
case 0: /* Child */
|
||||||
|
closelog();
|
||||||
|
setsid();
|
||||||
|
break;
|
||||||
|
case -1: /* Error */
|
||||||
|
syslog(LOG_ERR, "can't fork.");
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
default: /* Parent */
|
||||||
|
closelog();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restart syslog. */
|
||||||
|
openlog("powerd", LOG_CONS, LOG_DAEMON);
|
||||||
|
|
||||||
|
/* Now sample the DCD line. */
|
||||||
|
while(1) {
|
||||||
|
/* Get the status. */
|
||||||
|
ioctl(fd, TIOCMGET, &flags);
|
||||||
|
|
||||||
|
/* Check the connection: DSR should be high. */
|
||||||
|
tries = 0;
|
||||||
|
while((flags & TIOCM_DSR) == 0) {
|
||||||
|
/* Keep on trying, and warn every two minutes. */
|
||||||
|
if ((tries % 60) == 0)
|
||||||
|
syslog(LOG_ALERT, "UPS connection error");
|
||||||
|
sleep(2);
|
||||||
|
tries++;
|
||||||
|
ioctl(fd, TIOCMGET, &flags);
|
||||||
|
}
|
||||||
|
if (tries > 0)
|
||||||
|
syslog(LOG_ALERT, "UPS connection OK");
|
||||||
|
|
||||||
|
/* Calculate present status. */
|
||||||
|
status = (flags & TIOCM_CAR);
|
||||||
|
|
||||||
|
/* Did DCD drop to zero? Then the power has failed. */
|
||||||
|
if (oldstat != 0 && status == 0) {
|
||||||
|
count++;
|
||||||
|
if (count > 3)
|
||||||
|
powerfail(0);
|
||||||
|
else {
|
||||||
|
sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Did DCD come up again? Then the power is back. */
|
||||||
|
if (oldstat == 0 && status > 0) {
|
||||||
|
count++;
|
||||||
|
if (count > 3)
|
||||||
|
powerfail(1);
|
||||||
|
else {
|
||||||
|
sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Reset count, remember status and sleep 2 seconds. */
|
||||||
|
count = 0;
|
||||||
|
oldstat = status;
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
/* Never happens */
|
||||||
|
return(0);
|
||||||
|
}
|
58
obsolete/powerd.cfg
Normal file
58
obsolete/powerd.cfg
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Example configuration for power daemon.
|
||||||
|
# NOTE: this is not implemented yet, just a design.
|
||||||
|
#
|
||||||
|
# @(#) powerd.cfg 1.01 01-Oct-1994 MvS
|
||||||
|
#
|
||||||
|
|
||||||
|
# This is the setup section. It sets up the default line
|
||||||
|
# signals that your UPS likes to see.
|
||||||
|
[ setup ]
|
||||||
|
dtr = 1
|
||||||
|
rts = 1
|
||||||
|
baud = 2400
|
||||||
|
send "AAAA"
|
||||||
|
|
||||||
|
# Now: how to tell UPS to turn off the power.
|
||||||
|
[ powerdown ]
|
||||||
|
dtr = 0
|
||||||
|
send "BYE"
|
||||||
|
|
||||||
|
# How to monitor the UPS, or a remote UPS.
|
||||||
|
# Possible line signals: dcd cts dsr ring
|
||||||
|
#
|
||||||
|
# Comment out the parts you don't want.
|
||||||
|
#
|
||||||
|
# All of this (1, 2, 3) can be combined.
|
||||||
|
[ monitor ]
|
||||||
|
|
||||||
|
# First, do we want to broadcast the UPS status
|
||||||
|
# on ethernet when something happens?
|
||||||
|
# Comment out to disable.
|
||||||
|
# Syntax: address, portnumber
|
||||||
|
# address: broadcast adress on ethernet
|
||||||
|
# portnumber: unused priviliged port (under 1024)
|
||||||
|
broadcast = 10.0.33.255,15
|
||||||
|
|
||||||
|
# monitor type 1. This tells powerd to monitor line signals.
|
||||||
|
ok = dcd
|
||||||
|
fail = !dcd
|
||||||
|
lowbat = rts
|
||||||
|
|
||||||
|
# Monitor type 2. Tell powerd to look for data.
|
||||||
|
ok = "OK"
|
||||||
|
fail = "!"
|
||||||
|
|
||||||
|
# Monitor type 3. Listen to the ethernet.
|
||||||
|
#
|
||||||
|
# Warn_host is the hostname of the system with the UPS
|
||||||
|
# This is for security, so that someone on a DOS box
|
||||||
|
# can't spoof the powerd broadcast. The number after it
|
||||||
|
# is the portnumber to listen to (see above: broadcast).
|
||||||
|
#
|
||||||
|
# Note: if the broadcast address set above is enabled
|
||||||
|
# and we receive a message from a remote powerd, we check
|
||||||
|
# the received broadcast address. If this is the same
|
||||||
|
# as from the broadcast we just received,
|
||||||
|
# it will not be repeated (guess why).
|
||||||
|
remote = warn_host,15
|
||||||
|
|
70
obsolete/utmpdump.c.OLD
Normal file
70
obsolete/utmpdump.c.OLD
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* utmpdump Simple program to dump UTMP and WTMP files in
|
||||||
|
* raw format, so they can be examined.
|
||||||
|
*
|
||||||
|
* Version: @(#)utmpdump.c 13-Aug-1996 1.00 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-1996 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
void dump(fp)
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
struct utmp ut;
|
||||||
|
int f;
|
||||||
|
time_t tm;
|
||||||
|
|
||||||
|
while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) {
|
||||||
|
for(f = 0; f < 12; f++) if (ut.ut_line[f] == ' ') ut.ut_line[f] = '_';
|
||||||
|
for(f = 0; f < 8; f++) if (ut.ut_name[f] == ' ') ut.ut_name[f] = '_';
|
||||||
|
tm = ut.ut_time;
|
||||||
|
printf("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s]\n",
|
||||||
|
ut.ut_type, ut.ut_pid, ut.ut_id, ut.ut_user,
|
||||||
|
ut.ut_line, 4 + ctime(&tm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
int f;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
argc = 2;
|
||||||
|
argv[1] = UTMP_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(f = 1; f < argc; f++) {
|
||||||
|
if (strcmp(argv[f], "-") == 0) {
|
||||||
|
printf("Utmp dump of stdin\n");
|
||||||
|
dump(stdin);
|
||||||
|
} else if ((fp = fopen(argv[f], "r")) != NULL) {
|
||||||
|
printf("Utmp dump of %s\n", argv[f]);
|
||||||
|
dump(fp);
|
||||||
|
fclose(fp);
|
||||||
|
} else
|
||||||
|
perror(argv[f]);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
168
src/Makefile
Normal file
168
src/Makefile
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#
|
||||||
|
# Makefile Makefile for the systemV init suite.
|
||||||
|
# Targets: all compiles everything
|
||||||
|
# install installs the binaries (not the scripts)
|
||||||
|
# clean cleans up object files
|
||||||
|
# clobber really cleans up
|
||||||
|
#
|
||||||
|
# Version: @(#)Makefile 2.85-13 23-Mar-2004 miquels@cistron.nl
|
||||||
|
#
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -ansi -W -Wall -O2 -fomit-frame-pointer -D_GNU_SOURCE
|
||||||
|
LDFLAGS = -s
|
||||||
|
STATIC =
|
||||||
|
|
||||||
|
# For some known distributions we do not build all programs, otherwise we do.
|
||||||
|
BIN =
|
||||||
|
SBIN = init halt shutdown runlevel killall5
|
||||||
|
USRBIN = last mesg
|
||||||
|
|
||||||
|
MAN1 = last.1 lastb.1 mesg.1
|
||||||
|
MAN5 = initscript.5 inittab.5
|
||||||
|
MAN8 = halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8
|
||||||
|
MAN8 += shutdown.8 telinit.8
|
||||||
|
|
||||||
|
ifeq ($(DISTRO),)
|
||||||
|
BIN += mountpoint
|
||||||
|
SBIN += sulogin bootlogd
|
||||||
|
USRBIN += utmpdump wall
|
||||||
|
MAN1 += mountpoint.1 wall.1
|
||||||
|
MAN8 += sulogin.8 bootlogd.8
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DISTRO),Debian)
|
||||||
|
BIN += mountpoint
|
||||||
|
SBIN += sulogin bootlogd
|
||||||
|
MAN1 += mountpoint.1
|
||||||
|
MAN8 += sulogin.8 bootlogd.8
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DISTRO),Owl)
|
||||||
|
USRBIN += wall
|
||||||
|
MAN1 += wall.1
|
||||||
|
endif
|
||||||
|
|
||||||
|
BIN_OWNER = root
|
||||||
|
BIN_GROUP = root
|
||||||
|
BIN_COMBO = $(BIN_OWNER):$(BIN_GROUP)
|
||||||
|
STRIP = strip -s -R .comment
|
||||||
|
INSTALL_EXEC = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 755
|
||||||
|
INSTALL_DATA = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 644
|
||||||
|
MANDIR = /usr/share/man
|
||||||
|
|
||||||
|
ifeq ($(WITH_SELINUX),yes)
|
||||||
|
SELINUX_DEF=-DWITH_SELINUX
|
||||||
|
INIT_SELIBS=-lsepol -lselinux
|
||||||
|
SULOGIN_SELIBS=-lselinux
|
||||||
|
else
|
||||||
|
SELINUX_DEF=
|
||||||
|
INIT_SELIBS=
|
||||||
|
SULOGIN_SELIBS=
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Additional libs for GNU libc.
|
||||||
|
ifneq ($(wildcard /usr/lib/libcrypt.a),)
|
||||||
|
LCRYPT = -lcrypt
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(BIN) $(SBIN) $(USRBIN)
|
||||||
|
|
||||||
|
init: init.o init_utmp.o
|
||||||
|
$(CC) $(LDFLAGS) $(STATIC) -o $@ init.o init_utmp.o $(INIT_SELIBS)
|
||||||
|
|
||||||
|
halt: halt.o ifdown.o hddown.o utmp.o reboot.h
|
||||||
|
$(CC) $(LDFLAGS) -o $@ halt.o ifdown.o hddown.o utmp.o
|
||||||
|
|
||||||
|
last: last.o oldutmp.h
|
||||||
|
$(CC) $(LDFLAGS) -o $@ last.o
|
||||||
|
|
||||||
|
mesg: mesg.o
|
||||||
|
$(CC) $(LDFLAGS) -o $@ mesg.o
|
||||||
|
|
||||||
|
mountpoint: mountpoint.o
|
||||||
|
$(CC) $(LDFLAGS) -o $@ mountpoint.o
|
||||||
|
|
||||||
|
utmpdump: utmpdump.o
|
||||||
|
$(CC) $(LDFLAGS) -o $@ utmpdump.o
|
||||||
|
|
||||||
|
runlevel: runlevel.o
|
||||||
|
$(CC) $(LDFLAGS) -o $@ runlevel.o
|
||||||
|
|
||||||
|
sulogin: sulogin.o
|
||||||
|
$(CC) $(LDFLAGS) $(STATIC) $(SELINUX_DEF) -o $@ $^ $(LCRYPT) $(SULOGIN_SELIBS)
|
||||||
|
|
||||||
|
wall: dowall.o wall.o
|
||||||
|
$(CC) $(LDFLAGS) -o $@ dowall.o wall.o
|
||||||
|
|
||||||
|
shutdown: dowall.o shutdown.o utmp.o reboot.h
|
||||||
|
$(CC) $(LDFLAGS) -o $@ dowall.o shutdown.o utmp.o
|
||||||
|
|
||||||
|
bootlogd: bootlogd.o
|
||||||
|
$(CC) $(LDFLAGS) -o $@ bootlogd.o -lutil
|
||||||
|
|
||||||
|
sulogin.o: sulogin.c
|
||||||
|
$(CC) -c $(CFLAGS) $(SELINUX_DEF) sulogin.c
|
||||||
|
|
||||||
|
init.o: init.c init.h set.h reboot.h initreq.h
|
||||||
|
$(CC) -c $(CFLAGS) $(SELINUX_DEF) init.c
|
||||||
|
|
||||||
|
utmp.o: utmp.c init.h
|
||||||
|
$(CC) -c $(CFLAGS) utmp.c
|
||||||
|
|
||||||
|
init_utmp.o: utmp.c init.h
|
||||||
|
$(CC) -c $(CFLAGS) -DINIT_MAIN utmp.c -o init_utmp.o
|
||||||
|
|
||||||
|
cleanobjs:
|
||||||
|
rm -f *.o *.bak
|
||||||
|
|
||||||
|
clean: cleanobjs
|
||||||
|
@echo Type \"make clobber\" to really clean up.
|
||||||
|
|
||||||
|
clobber: cleanobjs
|
||||||
|
rm -f $(BIN) $(SBIN) $(USRBIN)
|
||||||
|
|
||||||
|
distclean: clobber
|
||||||
|
|
||||||
|
install:
|
||||||
|
for i in $(BIN); do \
|
||||||
|
$(STRIP) $$i ; \
|
||||||
|
$(INSTALL_EXEC) $$i $(ROOT)/bin/ ; \
|
||||||
|
done
|
||||||
|
for i in $(SBIN); do \
|
||||||
|
$(STRIP) $$i ; \
|
||||||
|
$(INSTALL_EXEC) $$i $(ROOT)/sbin/ ; \
|
||||||
|
done
|
||||||
|
for i in $(USRBIN); do \
|
||||||
|
$(STRIP) $$i ; \
|
||||||
|
$(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
|
||||||
|
done
|
||||||
|
# $(INSTALL_EXEC) etc/initscript.sample $(ROOT)/etc/
|
||||||
|
ln -sf halt $(ROOT)/sbin/reboot
|
||||||
|
ln -sf halt $(ROOT)/sbin/poweroff
|
||||||
|
ln -sf init $(ROOT)/sbin/telinit
|
||||||
|
ln -sf /sbin/killall5 $(ROOT)/bin/pidof
|
||||||
|
if [ ! -f $(ROOT)/usr/bin/lastb ]; then \
|
||||||
|
ln -sf last $(ROOT)/usr/bin/lastb; \
|
||||||
|
fi
|
||||||
|
$(INSTALL_DATA) initreq.h $(ROOT)/usr/include/
|
||||||
|
for i in $(MAN1); do \
|
||||||
|
$(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man1/; \
|
||||||
|
done
|
||||||
|
for i in $(MAN5); do \
|
||||||
|
$(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man5/; \
|
||||||
|
done
|
||||||
|
for i in $(MAN8); do \
|
||||||
|
$(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man8/; \
|
||||||
|
done
|
||||||
|
ifeq ($(ROOT),)
|
||||||
|
#
|
||||||
|
# This part is skipped on Debian systems, the
|
||||||
|
# debian.preinst script takes care of it.
|
||||||
|
@if [ ! -p /dev/initctl ]; then \
|
||||||
|
echo "Creating /dev/initctl"; \
|
||||||
|
rm -f /dev/initctl; \
|
||||||
|
mknod -m 600 /dev/initctl p; fi
|
||||||
|
endif
|
657
src/bootlogd.c
Normal file
657
src/bootlogd.c
Normal file
@ -0,0 +1,657 @@
|
|||||||
|
/*
|
||||||
|
* bootlogd.c Store output from the console during bootup into a file.
|
||||||
|
* The file is usually located on the /var partition, and
|
||||||
|
* gets written (and fsynced) as soon as possible.
|
||||||
|
*
|
||||||
|
* Version: @(#)bootlogd 2.86pre 12-Jan-2004 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Bugs: Uses openpty(), only available in glibc. Sorry.
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* *NOTE* *NOTE* *NOTE*
|
||||||
|
* This is a PROOF OF CONCEPT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
* I have bigger plans for Debian, but for now
|
||||||
|
* this has to do ;)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pty.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels@cistron.nl";
|
||||||
|
|
||||||
|
#define LOGFILE "/var/log/boot"
|
||||||
|
|
||||||
|
char ringbuf[32768];
|
||||||
|
char *endptr = ringbuf + sizeof(ringbuf);
|
||||||
|
char *inptr = ringbuf;
|
||||||
|
char *outptr = ringbuf;
|
||||||
|
|
||||||
|
int got_signal = 0;
|
||||||
|
int didnl = 1;
|
||||||
|
int createlogfile = 0;
|
||||||
|
int syncalot = 0;
|
||||||
|
|
||||||
|
struct line {
|
||||||
|
char buf[256];
|
||||||
|
int pos;
|
||||||
|
} line;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console devices as listed on the kernel command line and
|
||||||
|
* the mapping to actual devices in /dev
|
||||||
|
*/
|
||||||
|
struct consdev {
|
||||||
|
char *cmdline;
|
||||||
|
char *dev1;
|
||||||
|
char *dev2;
|
||||||
|
} consdev[] = {
|
||||||
|
{ "ttyB", "/dev/ttyB%s", NULL },
|
||||||
|
{ "ttySC", "/dev/ttySC%s", "/dev/ttsc/%s" },
|
||||||
|
{ "ttyS", "/dev/ttyS%s", "/dev/tts/%s" },
|
||||||
|
{ "tty", "/dev/tty%s", "/dev/vc/%s" },
|
||||||
|
{ "hvc", "/dev/hvc%s", "/dev/hvc/%s" },
|
||||||
|
{ NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Devices to try as console if not found on kernel command line.
|
||||||
|
* Tried from left to right (as opposed to kernel cmdline).
|
||||||
|
*/
|
||||||
|
char *defcons[] = { "tty0", "hvc0", "ttyS0", "ttySC0", "ttyB0", NULL };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Catch signals.
|
||||||
|
*/
|
||||||
|
void handler(int sig)
|
||||||
|
{
|
||||||
|
got_signal = sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan /dev and find the device name.
|
||||||
|
* Side-effect: directory is changed to /dev
|
||||||
|
*
|
||||||
|
* FIXME: scan subdirectories for devfs support ?
|
||||||
|
*/
|
||||||
|
int findtty(char *res, int rlen, dev_t dev)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
struct stat st;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (chdir("/dev") < 0 || (dir = opendir(".")) == NULL) {
|
||||||
|
perror("bootlogd: /dev");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
|
if (lstat(ent->d_name, &st) != 0)
|
||||||
|
continue;
|
||||||
|
if (!S_ISCHR(st.st_mode))
|
||||||
|
continue;
|
||||||
|
if (st.st_rdev == dev) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ent == NULL) {
|
||||||
|
fprintf(stderr, "bootlogd: cannot find console device "
|
||||||
|
"%d:%d in /dev\n", major(dev), minor(dev));
|
||||||
|
r = -1;
|
||||||
|
} else if (strlen(ent->d_name) + 5 >= rlen) {
|
||||||
|
fprintf(stderr, "bootlogd: console device name too long\n");
|
||||||
|
r = -1;
|
||||||
|
} else
|
||||||
|
snprintf(res, rlen, "/dev/%s", ent->d_name);
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For some reason, openpty() in glibc sometimes doesn't
|
||||||
|
* work at boot-time. It must be a bug with old-style pty
|
||||||
|
* names, as new-style (/dev/pts) is not available at that
|
||||||
|
* point. So, we find a pty/tty pair ourself if openpty()
|
||||||
|
* fails for whatever reason.
|
||||||
|
*/
|
||||||
|
int findpty(int *master, int *slave, char *name)
|
||||||
|
{
|
||||||
|
char pty[16];
|
||||||
|
char tty[16];
|
||||||
|
int i, j;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
if (openpty(master, slave, name, NULL, NULL) >= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
|
||||||
|
for (i = 'p'; i <= 'z'; i++) {
|
||||||
|
for (j = '0'; j <= 'f'; j++) {
|
||||||
|
if (j == '9' + 1) j = 'a';
|
||||||
|
sprintf(pty, "/dev/pty%c%c", i, j);
|
||||||
|
sprintf(tty, "/dev/tty%c%c", i, j);
|
||||||
|
if ((*master = open(pty, O_RDWR|O_NOCTTY)) >= 0) {
|
||||||
|
*slave = open(tty, O_RDWR|O_NOCTTY);
|
||||||
|
if (*slave >= 0) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) break;
|
||||||
|
}
|
||||||
|
if (found < 0) return -1;
|
||||||
|
|
||||||
|
if (name) strcpy(name, tty);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* See if a console taken from the kernel command line maps
|
||||||
|
* to a character device we know about, and if we can open it.
|
||||||
|
*/
|
||||||
|
int isconsole(char *s, char *res, int rlen)
|
||||||
|
{
|
||||||
|
struct consdev *c;
|
||||||
|
int l, sl, i, fd;
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
sl = strlen(s);
|
||||||
|
|
||||||
|
for (c = consdev; c->cmdline; c++) {
|
||||||
|
l = strlen(c->cmdline);
|
||||||
|
if (sl <= l) continue;
|
||||||
|
p = s + l;
|
||||||
|
if (strncmp(s, c->cmdline, l) != 0 || !isdigit(*p))
|
||||||
|
continue;
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
snprintf(res, rlen, i ? c->dev1 : c->dev2, p);
|
||||||
|
if ((q = strchr(res, ',')) != NULL) *q = 0;
|
||||||
|
if ((fd = open(res, O_RDONLY|O_NONBLOCK)) >= 0) {
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find out the _real_ console. Assume that stdin is connected to
|
||||||
|
* the console device (/dev/console).
|
||||||
|
*/
|
||||||
|
int consolename(char *res, int rlen)
|
||||||
|
{
|
||||||
|
#ifdef TIOCGDEV
|
||||||
|
unsigned int kdev;
|
||||||
|
#endif
|
||||||
|
struct stat st, st2;
|
||||||
|
char buf[256];
|
||||||
|
char *p;
|
||||||
|
int didmount = 0;
|
||||||
|
int n, r;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fstat(0, &st);
|
||||||
|
if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
|
||||||
|
/*
|
||||||
|
* Old kernel, can find real device easily.
|
||||||
|
*/
|
||||||
|
return findtty(res, rlen, st.st_rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TIOCGDEV
|
||||||
|
if (ioctl(0, TIOCGDEV, &kdev) == 0)
|
||||||
|
return findtty(res, rlen, (dev_t)kdev);
|
||||||
|
if (errno != ENOIOCTLCMD) return -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
/*
|
||||||
|
* Read /proc/cmdline.
|
||||||
|
*/
|
||||||
|
stat("/", &st);
|
||||||
|
if (stat("/proc", &st2) < 0) {
|
||||||
|
perror("bootlogd: /proc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (st.st_dev == st2.st_dev) {
|
||||||
|
if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
|
||||||
|
perror("bootlogd: mount /proc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
didmount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
r = -1;
|
||||||
|
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
|
||||||
|
perror("bootlogd: /proc/cmdline");
|
||||||
|
} else {
|
||||||
|
buf[0] = 0;
|
||||||
|
if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
|
||||||
|
r = 0;
|
||||||
|
else
|
||||||
|
perror("bootlogd: /proc/cmdline");
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
if (didmount) umount("/proc");
|
||||||
|
|
||||||
|
if (r < 0) return r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OK, so find console= in /proc/cmdline.
|
||||||
|
* Parse in reverse, opening as we go.
|
||||||
|
*/
|
||||||
|
p = buf + n;
|
||||||
|
*p-- = 0;
|
||||||
|
r = -1;
|
||||||
|
while (p >= buf) {
|
||||||
|
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
|
||||||
|
*p-- = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(p, "console=", 8) == 0 &&
|
||||||
|
isconsole(p + 8, res, rlen)) {
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == 0) return r;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay, no console on the command line -
|
||||||
|
* guess the default console.
|
||||||
|
*/
|
||||||
|
for (n = 0; defcons[n]; n++)
|
||||||
|
if (isconsole(defcons[n], res, rlen))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fprintf(stderr, "bootlogd: cannot deduce real console device\n");
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write data and make sure it's on disk.
|
||||||
|
*/
|
||||||
|
void writelog(FILE *fp, unsigned char *ptr, int len)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
char *s;
|
||||||
|
char tmp[8];
|
||||||
|
int olen = len;
|
||||||
|
int dosync = 0;
|
||||||
|
int tlen;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
tmp[0] = 0;
|
||||||
|
if (didnl) {
|
||||||
|
time(&t);
|
||||||
|
s = ctime(&t);
|
||||||
|
fprintf(fp, "%.24s: ", s);
|
||||||
|
didnl = 0;
|
||||||
|
}
|
||||||
|
switch (*ptr) {
|
||||||
|
case 27: /* ESC */
|
||||||
|
strcpy(tmp, "^[");
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
line.pos = 0;
|
||||||
|
break;
|
||||||
|
case 8: /* ^H */
|
||||||
|
if (line.pos > 0) line.pos--;
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
didnl = 1;
|
||||||
|
dosync = syncalot;
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
line.pos += (line.pos / 8 + 1) * 8;
|
||||||
|
if (line.pos >= sizeof(line.buf))
|
||||||
|
line.pos = sizeof(line.buf) - 1;
|
||||||
|
break;
|
||||||
|
case 32 ... 127:
|
||||||
|
case 161 ... 255:
|
||||||
|
tmp[0] = *ptr;
|
||||||
|
tmp[1] = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprintf(tmp, "\\%03o", *ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
len--;
|
||||||
|
|
||||||
|
tlen = strlen(tmp);
|
||||||
|
if (tlen && (line.pos + tlen < sizeof(line.buf))) {
|
||||||
|
memcpy(line.buf + line.pos, tmp, tlen);
|
||||||
|
line.pos += tlen;
|
||||||
|
}
|
||||||
|
if (didnl) {
|
||||||
|
fprintf(fp, "%s\n", line.buf);
|
||||||
|
memset(&line, 0, sizeof(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dosync) {
|
||||||
|
fflush(fp);
|
||||||
|
fdatasync(fileno(fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
outptr += olen;
|
||||||
|
if (outptr >= endptr)
|
||||||
|
outptr = ringbuf;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print usage message and exit.
|
||||||
|
*/
|
||||||
|
void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: bootlogd [-v] [-r] [-d] [-s] [-c] [-p pidfile] [-l logfile]\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_nb(char *buf)
|
||||||
|
{
|
||||||
|
int fd, n;
|
||||||
|
|
||||||
|
if ((fd = open(buf, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
|
||||||
|
return -1;
|
||||||
|
n = fcntl(fd, F_GETFL);
|
||||||
|
n &= ~(O_NONBLOCK);
|
||||||
|
fcntl(fd, F_SETFL, n);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We got a write error on the real console. If its an EIO,
|
||||||
|
* somebody hung up our filedescriptor, so try to re-open it.
|
||||||
|
*/
|
||||||
|
int write_err(int pts, int realfd, char *realcons, int e)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (e != EIO) {
|
||||||
|
werr:
|
||||||
|
close(pts);
|
||||||
|
fprintf(stderr, "bootlogd: writing to console: %s\n",
|
||||||
|
strerror(e));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(realfd);
|
||||||
|
if ((fd = open_nb(realcons)) < 0)
|
||||||
|
goto werr;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set fds;
|
||||||
|
char buf[1024];
|
||||||
|
char realcons[1024];
|
||||||
|
char *p;
|
||||||
|
char *logfile;
|
||||||
|
char *pidfile;
|
||||||
|
int rotate;
|
||||||
|
int dontfork;
|
||||||
|
int ptm, pts;
|
||||||
|
int realfd;
|
||||||
|
int n, m, i;
|
||||||
|
int todo;
|
||||||
|
|
||||||
|
fp = NULL;
|
||||||
|
logfile = LOGFILE;
|
||||||
|
pidfile = NULL;
|
||||||
|
rotate = 0;
|
||||||
|
dontfork = 0;
|
||||||
|
|
||||||
|
while ((i = getopt(argc, argv, "cdsl:p:rv")) != EOF) switch(i) {
|
||||||
|
case 'l':
|
||||||
|
logfile = optarg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rotate = 1;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
printf("%s\n", Version);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
pidfile = optarg;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
createlogfile = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
dontfork = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
syncalot = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (optind < argc) usage();
|
||||||
|
|
||||||
|
signal(SIGTERM, handler);
|
||||||
|
signal(SIGQUIT, handler);
|
||||||
|
signal(SIGINT, handler);
|
||||||
|
signal(SIGTTIN, SIG_IGN);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open console device directly.
|
||||||
|
*/
|
||||||
|
if (consolename(realcons, sizeof(realcons)) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (strcmp(realcons, "/dev/tty0") == 0)
|
||||||
|
strcpy(realcons, "/dev/tty1");
|
||||||
|
if (strcmp(realcons, "/dev/vc/0") == 0)
|
||||||
|
strcpy(realcons, "/dev/vc/1");
|
||||||
|
|
||||||
|
if ((realfd = open_nb(realcons)) < 0) {
|
||||||
|
fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Grab a pty, and redirect console messages to it.
|
||||||
|
*/
|
||||||
|
ptm = -1;
|
||||||
|
pts = -1;
|
||||||
|
buf[0] = 0;
|
||||||
|
if (findpty(&ptm, &pts, buf) < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"bootlogd: cannot allocate pseudo tty: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)ioctl(0, TIOCCONS, NULL);
|
||||||
|
#if 1
|
||||||
|
/* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
|
||||||
|
if ((n = open("/dev/tty0", O_RDWR)) >= 0) {
|
||||||
|
(void)ioctl(n, TIOCCONS, NULL);
|
||||||
|
close(n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ioctl(pts, TIOCCONS, NULL) < 0) {
|
||||||
|
fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n",
|
||||||
|
buf, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fork and write pidfile if needed.
|
||||||
|
*/
|
||||||
|
if (!dontfork) {
|
||||||
|
pid_t child_pid = fork();
|
||||||
|
switch (child_pid) {
|
||||||
|
case -1: /* I am parent and the attempt to create a child failed */
|
||||||
|
fprintf(stderr, "bootlogd: fork failed: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
case 0: /* I am the child */
|
||||||
|
break;
|
||||||
|
default: /* I am parent and got child's pid */
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setsid();
|
||||||
|
}
|
||||||
|
if (pidfile) {
|
||||||
|
unlink(pidfile);
|
||||||
|
if ((fp = fopen(pidfile, "w")) != NULL) {
|
||||||
|
fprintf(fp, "%d\n", (int)getpid());
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
fp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the console messages from the pty, and write
|
||||||
|
* to the real console and the logfile.
|
||||||
|
*/
|
||||||
|
while (!got_signal) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We timeout after 5 seconds if we still need to
|
||||||
|
* open the logfile. There might be buffered messages
|
||||||
|
* we want to write.
|
||||||
|
*/
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 500000;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(ptm, &fds);
|
||||||
|
if (select(ptm + 1, &fds, NULL, NULL, &tv) == 1) {
|
||||||
|
/*
|
||||||
|
* See how much space there is left, read.
|
||||||
|
*/
|
||||||
|
if ((n = read(ptm, inptr, endptr - inptr)) >= 0) {
|
||||||
|
/*
|
||||||
|
* Write data (in chunks if needed)
|
||||||
|
* to the real output device.
|
||||||
|
*/
|
||||||
|
m = n;
|
||||||
|
p = inptr;
|
||||||
|
while (m > 0) {
|
||||||
|
i = write(realfd, p, m);
|
||||||
|
if (i >= 0) {
|
||||||
|
m -= i;
|
||||||
|
p += i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Handle EIO (somebody hung
|
||||||
|
* up our filedescriptor)
|
||||||
|
*/
|
||||||
|
realfd = write_err(pts, realfd,
|
||||||
|
realcons, errno);
|
||||||
|
if (realfd >= 0) continue;
|
||||||
|
got_signal = 1; /* Not really */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment buffer position. Handle
|
||||||
|
* wraps, and also drag output pointer
|
||||||
|
* along if we cross it.
|
||||||
|
*/
|
||||||
|
inptr += n;
|
||||||
|
if (inptr - n < outptr && inptr > outptr)
|
||||||
|
outptr = inptr;
|
||||||
|
if (inptr >= endptr)
|
||||||
|
inptr = ringbuf;
|
||||||
|
if (outptr >= endptr)
|
||||||
|
outptr = ringbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perhaps we need to open the logfile.
|
||||||
|
*/
|
||||||
|
if (fp == NULL && access(logfile, F_OK) == 0) {
|
||||||
|
if (rotate) {
|
||||||
|
snprintf(buf, sizeof(buf), "%s~", logfile);
|
||||||
|
rename(logfile, buf);
|
||||||
|
}
|
||||||
|
fp = fopen(logfile, "a");
|
||||||
|
}
|
||||||
|
if (fp == NULL && createlogfile)
|
||||||
|
fp = fopen(logfile, "a");
|
||||||
|
|
||||||
|
if (inptr >= outptr)
|
||||||
|
todo = inptr - outptr;
|
||||||
|
else
|
||||||
|
todo = endptr - outptr;
|
||||||
|
if (fp && todo)
|
||||||
|
writelog(fp, outptr, todo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
if (!didnl) fputc('\n', fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pts);
|
||||||
|
close(ptm);
|
||||||
|
close(realfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
236
src/dowall.c
Normal file
236
src/dowall.c
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
* dowall.c Write to all users on the system.
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Version: @(#)dowall.c 2.85-5 02-Jul-2003 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2003 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
static sigjmp_buf jbuf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alarm handler
|
||||||
|
*/
|
||||||
|
/*ARGSUSED*/
|
||||||
|
static void handler(int arg)
|
||||||
|
{
|
||||||
|
siglongjmp(jbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a text, escape all characters not in Latin-1.
|
||||||
|
*/
|
||||||
|
static void feputs(char *line, FILE *fp)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
for (p = (unsigned char *)line; *p; p++) {
|
||||||
|
if (strchr("\t\r\n", *p) ||
|
||||||
|
(*p >= 32 && *p <= 127) || (*p >= 160)) {
|
||||||
|
fputc(*p, fp);
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "^%c", (*p & 0x1f) + 'A' - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fflush(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void getuidtty(char **userp, char **ttyp)
|
||||||
|
{
|
||||||
|
struct passwd *pwd;
|
||||||
|
uid_t uid;
|
||||||
|
char *tty;
|
||||||
|
static char uidbuf[32];
|
||||||
|
static char ttynm[UT_LINESIZE + 4];
|
||||||
|
static int init = 0;
|
||||||
|
|
||||||
|
if (!init) {
|
||||||
|
|
||||||
|
uid = getuid();
|
||||||
|
if ((pwd = getpwuid(uid)) != NULL) {
|
||||||
|
uidbuf[0] = 0;
|
||||||
|
strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
|
||||||
|
} else {
|
||||||
|
sprintf(uidbuf, uid ? "uid %d" : "root", (int)uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tty = ttyname(0)) != NULL) {
|
||||||
|
if (strncmp(tty, "/dev/", 5) == 0)
|
||||||
|
tty += 5;
|
||||||
|
sprintf(ttynm, "(%.28s) ", tty);
|
||||||
|
} else
|
||||||
|
ttynm[0] = 0;
|
||||||
|
init++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*userp = uidbuf;
|
||||||
|
*ttyp = ttynm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether given filename looks like tty device.
|
||||||
|
*/
|
||||||
|
static int file_isatty(const char *fname)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int major;
|
||||||
|
|
||||||
|
if (stat(fname, &st) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It would be an impossible task to list all major/minors
|
||||||
|
* of tty devices here, so we just exclude the obvious
|
||||||
|
* majors of which just opening has side-effects:
|
||||||
|
* printers and tapes.
|
||||||
|
*/
|
||||||
|
major = major(st.st_dev);
|
||||||
|
if (major == 1 || major == 2 || major == 6 || major == 9 ||
|
||||||
|
major == 12 || major == 16 || major == 21 || major == 27 ||
|
||||||
|
major == 37 || major == 96 || major == 97 || major == 206 ||
|
||||||
|
major == 230) return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wall function.
|
||||||
|
*/
|
||||||
|
void wall(char *text, int fromshutdown, int remote)
|
||||||
|
{
|
||||||
|
FILE *tp;
|
||||||
|
struct sigaction sa;
|
||||||
|
struct utmp *utmp;
|
||||||
|
time_t t;
|
||||||
|
char term[UT_LINESIZE+6];
|
||||||
|
char line[81];
|
||||||
|
char hostname[256]; /* HOST_NAME_MAX+1 */
|
||||||
|
char *date, *p;
|
||||||
|
char *user, *tty;
|
||||||
|
int fd, flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure tp and fd aren't in a register. Some versions
|
||||||
|
* of gcc clobber those after longjmp (or so I understand).
|
||||||
|
*/
|
||||||
|
(void) &tp;
|
||||||
|
(void) &fd;
|
||||||
|
|
||||||
|
getuidtty(&user, &tty);
|
||||||
|
|
||||||
|
/* Get and report current hostname, to make it easier to find
|
||||||
|
out which machine is being shut down. */
|
||||||
|
if (0 != gethostname(hostname, sizeof(hostname))) {
|
||||||
|
strncpy(hostname, "[unknown]", sizeof(hostname)-1);
|
||||||
|
}
|
||||||
|
/* If hostname is truncated, it is unspecified if the string
|
||||||
|
is null terminated or not. Make sure we know it is null
|
||||||
|
terminated. */
|
||||||
|
hostname[sizeof(hostname)-1] = 0;
|
||||||
|
|
||||||
|
/* Get the time */
|
||||||
|
time(&t);
|
||||||
|
date = ctime(&t);
|
||||||
|
for(p = date; *p && *p != '\n'; p++)
|
||||||
|
;
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
if (remote) {
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"\007\r\nRemote broadcast message (%s):\r\n\r\n",
|
||||||
|
date);
|
||||||
|
} else {
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n",
|
||||||
|
user, hostname, tty, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fork to avoid us hanging in a write()
|
||||||
|
*/
|
||||||
|
if (fork() != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = handler;
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(SIGALRM, &sa, NULL);
|
||||||
|
|
||||||
|
setutent();
|
||||||
|
|
||||||
|
while ((utmp = getutent()) != NULL) {
|
||||||
|
if(utmp->ut_type != USER_PROCESS ||
|
||||||
|
utmp->ut_user[0] == 0) continue;
|
||||||
|
if (strncmp(utmp->ut_line, "/dev/", 5) == 0) {
|
||||||
|
term[0] = 0;
|
||||||
|
strncat(term, utmp->ut_line, sizeof(term)-1);
|
||||||
|
} else
|
||||||
|
snprintf(term, sizeof(term), "/dev/%.*s",
|
||||||
|
UT_LINESIZE, utmp->ut_line);
|
||||||
|
if (strstr(term, "/../")) continue;
|
||||||
|
|
||||||
|
fd = -1;
|
||||||
|
tp = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open it non-delay
|
||||||
|
*/
|
||||||
|
if (sigsetjmp(jbuf, 1) == 0) {
|
||||||
|
alarm(2);
|
||||||
|
flags = O_WRONLY|O_NDELAY|O_NOCTTY;
|
||||||
|
if (file_isatty(term) &&
|
||||||
|
(fd = open(term, flags)) >= 0) {
|
||||||
|
if (isatty(fd) &&
|
||||||
|
(tp = fdopen(fd, "w")) != NULL) {
|
||||||
|
fputs(line, tp);
|
||||||
|
feputs(text, tp);
|
||||||
|
fflush(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alarm(0);
|
||||||
|
if (fd >= 0) close(fd);
|
||||||
|
if (tp != NULL) fclose(tp);
|
||||||
|
}
|
||||||
|
endutent();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
312
src/halt.c
Normal file
312
src/halt.c
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* Halt Stop the system running.
|
||||||
|
* It re-enables CTRL-ALT-DEL, so that a hard reboot can
|
||||||
|
* be done. If called as reboot, it will reboot the system.
|
||||||
|
*
|
||||||
|
* If the system is not in runlevel 0 or 6, halt will just
|
||||||
|
* execute a "shutdown -h" to halt the system, and reboot will
|
||||||
|
* execute an "shutdown -r". This is for compatibility with
|
||||||
|
* sysvinit 2.4.
|
||||||
|
*
|
||||||
|
* Usage: halt [-n] [-w] [-d] [-f] [-h] [-i] [-p]
|
||||||
|
* -n: don't sync before halting the system
|
||||||
|
* -w: only write a wtmp reboot record and exit.
|
||||||
|
* -d: don't write a wtmp record.
|
||||||
|
* -f: force halt/reboot, don't call shutdown.
|
||||||
|
* -h: put harddisks in standby mode
|
||||||
|
* -i: shut down all network interfaces.
|
||||||
|
* -p: power down the system (if possible, otherwise halt).
|
||||||
|
*
|
||||||
|
* Reboot and halt are both this program. Reboot
|
||||||
|
* is just a link to halt. Invoking the program
|
||||||
|
* as poweroff implies the -p option.
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Version: 2.86, 30-Jul-2004
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/times.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include "reboot.h"
|
||||||
|
|
||||||
|
char *Version = "@(#)halt 2.86 31-Jul-2004 miquels@cistron.nl";
|
||||||
|
char *progname;
|
||||||
|
|
||||||
|
#define KERNEL_MONITOR 1 /* If halt() puts you into the kernel monitor. */
|
||||||
|
#define RUNLVL_PICKY 0 /* Be picky about the runlevel */
|
||||||
|
|
||||||
|
extern int ifdown(void);
|
||||||
|
extern int hddown(void);
|
||||||
|
extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send usage message.
|
||||||
|
*/
|
||||||
|
void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n",
|
||||||
|
progname, strcmp(progname, "halt") ? "" : " [-p]");
|
||||||
|
fprintf(stderr, "\t-n: don't sync before halting the system\n");
|
||||||
|
fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n");
|
||||||
|
fprintf(stderr, "\t-d: don't write a wtmp record.\n");
|
||||||
|
fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n");
|
||||||
|
fprintf(stderr, "\t-h: put harddisks in standby mode.\n");
|
||||||
|
fprintf(stderr, "\t-i: shut down all network interfaces.\n");
|
||||||
|
if (!strcmp(progname, "halt"))
|
||||||
|
fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we were started directly from init.
|
||||||
|
* Get the runlevel from /var/run/utmp or the environment.
|
||||||
|
*/
|
||||||
|
int get_runlevel(void)
|
||||||
|
{
|
||||||
|
struct utmp *ut;
|
||||||
|
char *r;
|
||||||
|
#if RUNLVL_PICKY
|
||||||
|
time_t boottime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First see if we were started directly from init.
|
||||||
|
*/
|
||||||
|
if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL)
|
||||||
|
return *r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hmm, failed - read runlevel from /var/run/utmp..
|
||||||
|
*/
|
||||||
|
#if RUNLVL_PICKY
|
||||||
|
/*
|
||||||
|
* Get boottime from the kernel.
|
||||||
|
*/
|
||||||
|
time(&boottime);
|
||||||
|
boottime -= (times(NULL) / HZ);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find runlevel in utmp.
|
||||||
|
*/
|
||||||
|
setutent();
|
||||||
|
while ((ut = getutent()) != NULL) {
|
||||||
|
#if RUNLVL_PICKY
|
||||||
|
/*
|
||||||
|
* Only accept value if it's from after boottime.
|
||||||
|
*/
|
||||||
|
if (ut->ut_type == RUN_LVL && ut->ut_time > boottime)
|
||||||
|
return (ut->ut_pid & 255);
|
||||||
|
#else
|
||||||
|
if (ut->ut_type == RUN_LVL)
|
||||||
|
return (ut->ut_pid & 255);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
endutent();
|
||||||
|
|
||||||
|
/* This should not happen but warn the user! */
|
||||||
|
fprintf(stderr, "WARNING: could not determine runlevel"
|
||||||
|
" - doing soft %s\n", progname);
|
||||||
|
fprintf(stderr, " (it's better to use shutdown instead of %s"
|
||||||
|
" from the command line)\n", progname);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch to another runlevel.
|
||||||
|
*/
|
||||||
|
void do_shutdown(char *fl, char *tm)
|
||||||
|
{
|
||||||
|
char *args[8];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
args[i++] = "shutdown";
|
||||||
|
args[i++] = fl;
|
||||||
|
if (tm) {
|
||||||
|
args[i++] = "-t";
|
||||||
|
args[i++] = tm;
|
||||||
|
}
|
||||||
|
args[i++] = "now";
|
||||||
|
args[i++] = NULL;
|
||||||
|
|
||||||
|
execv("/sbin/shutdown", args);
|
||||||
|
execv("/etc/shutdown", args);
|
||||||
|
execv("/bin/shutdown", args);
|
||||||
|
|
||||||
|
perror("shutdown");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main program.
|
||||||
|
* Write a wtmp entry and reboot cq. halt.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int do_reboot = 0;
|
||||||
|
int do_sync = 1;
|
||||||
|
int do_wtmp = 1;
|
||||||
|
int do_nothing = 0;
|
||||||
|
int do_hard = 0;
|
||||||
|
int do_ifdown = 0;
|
||||||
|
int do_hddown = 0;
|
||||||
|
int do_poweroff = 0;
|
||||||
|
int c;
|
||||||
|
char *tm = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find out who we are
|
||||||
|
*/
|
||||||
|
/* Remove dash passed on in argv[0] when used as login shell. */
|
||||||
|
if (argv[0][0] == '-') argv[0]++;
|
||||||
|
if ((progname = strrchr(argv[0], '/')) != NULL)
|
||||||
|
progname++;
|
||||||
|
else
|
||||||
|
progname = argv[0];
|
||||||
|
|
||||||
|
if (!strcmp(progname, "reboot")) do_reboot = 1;
|
||||||
|
if (!strcmp(progname, "poweroff")) do_poweroff = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get flags
|
||||||
|
*/
|
||||||
|
while((c = getopt(argc, argv, ":ihdfnpwt:")) != EOF) {
|
||||||
|
switch(c) {
|
||||||
|
case 'n':
|
||||||
|
do_sync = 0;
|
||||||
|
do_wtmp = 0;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
do_nothing = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
do_wtmp = 0;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
do_hard = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
do_ifdown = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
do_hddown = 1;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
do_poweroff = 1;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
tm = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argc != optind) usage();
|
||||||
|
|
||||||
|
if (geteuid() != 0) {
|
||||||
|
fprintf(stderr, "%s: must be superuser.\n", progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)chdir("/");
|
||||||
|
|
||||||
|
if (!do_hard && !do_nothing) {
|
||||||
|
/*
|
||||||
|
* See if we are in runlevel 0 or 6.
|
||||||
|
*/
|
||||||
|
c = get_runlevel();
|
||||||
|
if (c != '0' && c != '6')
|
||||||
|
do_shutdown(do_reboot ? "-r" : "-h", tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record the fact that we're going down
|
||||||
|
*/
|
||||||
|
if (do_wtmp)
|
||||||
|
write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exit if all we wanted to do was write a wtmp record.
|
||||||
|
*/
|
||||||
|
if (do_nothing && !do_hddown && !do_ifdown) exit(0);
|
||||||
|
|
||||||
|
if (do_sync) {
|
||||||
|
sync();
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_ifdown)
|
||||||
|
(void)ifdown();
|
||||||
|
|
||||||
|
if (do_hddown)
|
||||||
|
(void)hddown();
|
||||||
|
|
||||||
|
if (do_nothing) exit(0);
|
||||||
|
|
||||||
|
if (do_reboot) {
|
||||||
|
init_reboot(BMAGIC_REBOOT);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Turn on hard reboot, CTRL-ALT-DEL will reboot now
|
||||||
|
*/
|
||||||
|
#ifdef BMAGIC_HARD
|
||||||
|
init_reboot(BMAGIC_HARD);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop init; it is insensitive to the signals sent
|
||||||
|
* by the kernel.
|
||||||
|
*/
|
||||||
|
kill(1, SIGTSTP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Halt or poweroff.
|
||||||
|
*/
|
||||||
|
if (do_poweroff)
|
||||||
|
init_reboot(BMAGIC_POWEROFF);
|
||||||
|
/*
|
||||||
|
* Fallthrough if failed.
|
||||||
|
*/
|
||||||
|
init_reboot(BMAGIC_HALT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we return, we (c)ontinued from the kernel monitor.
|
||||||
|
*/
|
||||||
|
#ifdef BMAGIC_SOFT
|
||||||
|
init_reboot(BMAGIC_SOFT);
|
||||||
|
#endif
|
||||||
|
kill(1, SIGCONT);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
512
src/hddown.c
Normal file
512
src/hddown.c
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
* hddown.c Find all disks on the system and
|
||||||
|
* shut them down.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
char *v_hddown = "@(#)hddown.c 1.02 22-Apr-2003 miquels@cistron.nl";
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/hdreg.h>
|
||||||
|
|
||||||
|
#define USE_SYSFS
|
||||||
|
#ifdef USE_SYSFS
|
||||||
|
/*
|
||||||
|
* sysfs part Find all disks on the system, list out IDE and unmanaged
|
||||||
|
* SATA disks, flush the cache of those and shut them down.
|
||||||
|
* Author: Werner Fink <werner@suse.de>, 2007/06/12
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
#include <byteswap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SYS_BLK "/sys/block"
|
||||||
|
#define SYS_CLASS "/sys/class/scsi_disk"
|
||||||
|
#define DEV_BASE "/dev"
|
||||||
|
#define ISSPACE(c) (((c)==' ')||((c)=='\n')||((c)=='\t')||((c)=='\v')||((c)=='\r')||((c)=='\f'))
|
||||||
|
|
||||||
|
/* Used in flush_cache_ext(), compare with <linux/hdreg.h> */
|
||||||
|
#define IDBYTES 512
|
||||||
|
#define MASK_EXT 0xE000 /* Bit 15 shall be zero, bit 14 shall be one, bit 13 flush cache ext */
|
||||||
|
#define TEST_EXT 0x6000
|
||||||
|
|
||||||
|
/* Maybe set in list_disks() and used in do_standby_idedisk() */
|
||||||
|
#define DISK_IS_IDE 0x00000001
|
||||||
|
#define DISK_IS_SATA 0x00000002
|
||||||
|
#define DISK_EXTFLUSH 0x00000004
|
||||||
|
|
||||||
|
static char *strstrip(char *str);
|
||||||
|
static FILE *hdopen(const char* const format, const char* const name);
|
||||||
|
static int flush_cache_ext(const char *device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all disks through /sys/block.
|
||||||
|
*/
|
||||||
|
static char *list_disks(DIR* blk, unsigned int* flags)
|
||||||
|
{
|
||||||
|
struct dirent *d;
|
||||||
|
|
||||||
|
while ((d = readdir(blk))) {
|
||||||
|
*flags = 0;
|
||||||
|
if (d->d_name[1] == 'd' && (d->d_name[0] == 'h' || d->d_name[0] == 's')) {
|
||||||
|
char buf[NAME_MAX+1], lnk[NAME_MAX+1], *ptr;
|
||||||
|
struct stat st;
|
||||||
|
FILE *fp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
|
||||||
|
if ((long)fp <= 0) {
|
||||||
|
if ((long)fp < 0)
|
||||||
|
goto empty; /* error */
|
||||||
|
continue; /* no entry `removable' */
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = getc(fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (ret != '0')
|
||||||
|
continue; /* not a hard disk */
|
||||||
|
|
||||||
|
if (d->d_name[0] == 'h') {
|
||||||
|
(*flags) |= DISK_IS_IDE;
|
||||||
|
if ((ret = flush_cache_ext(d->d_name))) {
|
||||||
|
if (ret < 0)
|
||||||
|
goto empty;
|
||||||
|
(*flags) |= DISK_EXTFLUSH;
|
||||||
|
}
|
||||||
|
break; /* old IDE disk not managed by kernel, out here */
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/device", d->d_name);
|
||||||
|
if ((ret >= sizeof(buf)) || (ret < 0))
|
||||||
|
goto empty; /* error */
|
||||||
|
|
||||||
|
ret = readlink(buf, lnk, sizeof(lnk));
|
||||||
|
if (ret >= sizeof(lnk))
|
||||||
|
goto empty; /* error */
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
goto empty; /* error */
|
||||||
|
continue; /* no entry `device' */
|
||||||
|
}
|
||||||
|
lnk[ret] = '\0';
|
||||||
|
|
||||||
|
ptr = basename(lnk);
|
||||||
|
if (!ptr || !*ptr)
|
||||||
|
continue; /* should not happen */
|
||||||
|
|
||||||
|
ret = snprintf(buf, sizeof(buf), SYS_CLASS "/%s/manage_start_stop", ptr);
|
||||||
|
if ((ret >= sizeof(buf)) || (ret < 0))
|
||||||
|
goto empty; /* error */
|
||||||
|
|
||||||
|
ret = stat(buf, &st);
|
||||||
|
if (ret == 0)
|
||||||
|
continue; /* disk found but managed by kernel */
|
||||||
|
|
||||||
|
if (errno != ENOENT)
|
||||||
|
goto empty; /* error */
|
||||||
|
|
||||||
|
fp = hdopen(SYS_BLK "/%s/device/vendor", d->d_name);
|
||||||
|
if ((long)fp <= 0) {
|
||||||
|
if ((long)fp < 0)
|
||||||
|
goto empty; /* error */
|
||||||
|
continue; /* no entry `device/vendor' */
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = fgets(buf, sizeof(buf), fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (ptr == (char*)0)
|
||||||
|
continue; /* should not happen */
|
||||||
|
|
||||||
|
ptr = strstrip(buf);
|
||||||
|
if (*ptr == '\0')
|
||||||
|
continue; /* should not happen */
|
||||||
|
|
||||||
|
if (strncmp(buf, "ATA", sizeof(buf)))
|
||||||
|
continue; /* no SATA but a real SCSI disk */
|
||||||
|
|
||||||
|
(*flags) |= (DISK_IS_IDE|DISK_IS_SATA);
|
||||||
|
if ((ret = flush_cache_ext(d->d_name))) {
|
||||||
|
if (ret < 0)
|
||||||
|
goto empty;
|
||||||
|
(*flags) |= DISK_EXTFLUSH;
|
||||||
|
}
|
||||||
|
break; /* new SATA disk to shutdown, out here */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d == (struct dirent*)0)
|
||||||
|
goto empty;
|
||||||
|
return d->d_name;
|
||||||
|
empty:
|
||||||
|
return (char*)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put an disk in standby mode.
|
||||||
|
* Code stolen from hdparm.c
|
||||||
|
*/
|
||||||
|
static int do_standby_idedisk(char *device, unsigned int flags)
|
||||||
|
{
|
||||||
|
#ifndef WIN_STANDBYNOW1
|
||||||
|
#define WIN_STANDBYNOW1 0xE0
|
||||||
|
#endif
|
||||||
|
#ifndef WIN_STANDBYNOW2
|
||||||
|
#define WIN_STANDBYNOW2 0x94
|
||||||
|
#endif
|
||||||
|
#ifndef WIN_FLUSH_CACHE_EXT
|
||||||
|
#define WIN_FLUSH_CACHE_EXT 0xEA
|
||||||
|
#endif
|
||||||
|
#ifndef WIN_FLUSH_CACHE
|
||||||
|
#define WIN_FLUSH_CACHE 0xE7
|
||||||
|
#endif
|
||||||
|
unsigned char flush1[4] = {WIN_FLUSH_CACHE_EXT,0,0,0};
|
||||||
|
unsigned char flush2[4] = {WIN_FLUSH_CACHE,0,0,0};
|
||||||
|
unsigned char stdby1[4] = {WIN_STANDBYNOW1,0,0,0};
|
||||||
|
unsigned char stdby2[4] = {WIN_STANDBYNOW2,0,0,0};
|
||||||
|
char buf[NAME_MAX+1];
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
|
||||||
|
if ((ret >= sizeof(buf)) || (ret < 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((fd = open(buf, O_RDWR)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (flags & DISK_EXTFLUSH) {
|
||||||
|
case DISK_EXTFLUSH:
|
||||||
|
if (ioctl(fd, HDIO_DRIVE_CMD, &flush1) == 0)
|
||||||
|
break;
|
||||||
|
/* Extend flush rejected, try standard flush */
|
||||||
|
default:
|
||||||
|
ioctl(fd, HDIO_DRIVE_CMD, &flush2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl(fd, HDIO_DRIVE_CMD, &stdby1) &&
|
||||||
|
ioctl(fd, HDIO_DRIVE_CMD, &stdby2);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List all disks and put them in standby mode.
|
||||||
|
* This has the side-effect of flushing the writecache,
|
||||||
|
* which is exactly what we want on poweroff.
|
||||||
|
*/
|
||||||
|
int hddown(void)
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
char *disk;
|
||||||
|
DIR *blk;
|
||||||
|
|
||||||
|
if ((blk = opendir(SYS_BLK)) == (DIR*)0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((disk = list_disks(blk, &flags)))
|
||||||
|
do_standby_idedisk(disk, flags);
|
||||||
|
|
||||||
|
return closedir(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Strip off trailing white spaces
|
||||||
|
*/
|
||||||
|
static char *strstrip(char *str)
|
||||||
|
{
|
||||||
|
const size_t len = strlen(str);
|
||||||
|
if (len) {
|
||||||
|
char* end = str + len - 1;
|
||||||
|
while ((end != str) && ISSPACE(*end))
|
||||||
|
end--;
|
||||||
|
*(end + 1) = '\0'; /* remove trailing white spaces */
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a sysfs file without getting a controlling tty
|
||||||
|
* and return FILE* pointer.
|
||||||
|
*/
|
||||||
|
static FILE *hdopen(const char* const format, const char* const name)
|
||||||
|
{
|
||||||
|
char buf[NAME_MAX+1];
|
||||||
|
FILE *fp = (FILE*)-1;
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
ret = snprintf(buf, sizeof(buf), format, name);
|
||||||
|
if ((ret >= sizeof(buf)) || (ret < 0))
|
||||||
|
goto error; /* error */
|
||||||
|
|
||||||
|
fd = open(buf, O_RDONLY|O_NOCTTY);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
goto error; /* error */
|
||||||
|
fp = (FILE*)0;
|
||||||
|
goto error; /* no entry `removable' */
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fdopen(fd, "r");
|
||||||
|
if (fp == (FILE*)0)
|
||||||
|
close(fd); /* should not happen */
|
||||||
|
error:
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check IDE/(S)ATA hard disk identity for
|
||||||
|
* the FLUSH CACHE EXT bit set.
|
||||||
|
*/
|
||||||
|
static int flush_cache_ext(const char *device)
|
||||||
|
{
|
||||||
|
#ifndef WIN_IDENTIFY
|
||||||
|
#define WIN_IDENTIFY 0xEC
|
||||||
|
#endif
|
||||||
|
unsigned char args[4+IDBYTES];
|
||||||
|
unsigned short *id = (unsigned short*)(&args[4]);
|
||||||
|
char buf[NAME_MAX+1], *ptr;
|
||||||
|
int fd = -1, ret = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = hdopen(SYS_BLK "/%s/size", device);
|
||||||
|
if ((long)fp <= 0) {
|
||||||
|
if ((long)fp < 0)
|
||||||
|
return -1; /* error */
|
||||||
|
goto out; /* no entry `size' */
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = fgets(buf, sizeof(buf), fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (ptr == (char*)0)
|
||||||
|
goto out; /* should not happen */
|
||||||
|
|
||||||
|
ptr = strstrip(buf);
|
||||||
|
if (*ptr == '\0')
|
||||||
|
goto out; /* should not happen */
|
||||||
|
|
||||||
|
if ((size_t)atoll(buf) < (1<<28))
|
||||||
|
goto out; /* small disk */
|
||||||
|
|
||||||
|
ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
|
||||||
|
if ((ret >= sizeof(buf)) || (ret < 0))
|
||||||
|
return -1; /* error */
|
||||||
|
|
||||||
|
if ((fd = open(buf, O_RDONLY|O_NONBLOCK)) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
memset(&args[0], 0, sizeof(args));
|
||||||
|
args[0] = WIN_IDENTIFY;
|
||||||
|
args[3] = 1;
|
||||||
|
if (ioctl(fd, HDIO_DRIVE_CMD, &args))
|
||||||
|
goto out;
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
# if 0
|
||||||
|
{
|
||||||
|
const unsigned short *end = id + IDBYTES/2;
|
||||||
|
const unsigned short *from = id;
|
||||||
|
unsigned short *to = id;
|
||||||
|
|
||||||
|
while (from < end)
|
||||||
|
*to++ = bswap_16(*from++);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
id[83] = bswap_16(id[83]);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
if ((id[83] & MASK_EXT) == TEST_EXT)
|
||||||
|
ret = 1;
|
||||||
|
out:
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else /* ! USE_SYSFS */
|
||||||
|
#define MAX_DISKS 64
|
||||||
|
#define PROC_IDE "/proc/ide"
|
||||||
|
#define DEV_BASE "/dev"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all IDE disks through /proc.
|
||||||
|
*/
|
||||||
|
static int find_idedisks(const char **dev, int maxdev, int *count)
|
||||||
|
{
|
||||||
|
DIR *dd;
|
||||||
|
FILE *fp;
|
||||||
|
struct dirent *d;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
if ((dd = opendir(PROC_IDE)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (*count < maxdev && (d = readdir(dd)) != NULL) {
|
||||||
|
if (strncmp(d->d_name, "hd", 2) != 0)
|
||||||
|
continue;
|
||||||
|
buf[0] = 0;
|
||||||
|
snprintf(buf, sizeof(buf), PROC_IDE "/%s/media", d->d_name);
|
||||||
|
if ((fp = fopen(buf, "r")) == NULL)
|
||||||
|
continue;
|
||||||
|
if (fgets(buf, sizeof(buf), fp) == 0 ||
|
||||||
|
strcmp(buf, "disk\n") != 0) {
|
||||||
|
fclose(fp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
|
||||||
|
dev[(*count)++] = strdup(buf);
|
||||||
|
}
|
||||||
|
closedir(dd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all SCSI/SATA disks.
|
||||||
|
*/
|
||||||
|
static int find_scsidisks(const char **dev, int maxdev, int *count)
|
||||||
|
{
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sda";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdb";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdc";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdd";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sde";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdf";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdg";
|
||||||
|
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdh";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the device node of a disk.
|
||||||
|
*/
|
||||||
|
static int open_disk(const char *device)
|
||||||
|
{
|
||||||
|
return open(device, O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open device nodes of all disks, and store the file descriptors in fds.
|
||||||
|
* This has to be done in advance because accessing the device nodes
|
||||||
|
* might cause a disk to spin back up.
|
||||||
|
*/
|
||||||
|
static int open_disks(const char **disks, int *fds, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
fds[i] = open_disk(disks[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put an IDE/SCSI/SATA disk in standby mode.
|
||||||
|
* Code stolen from hdparm.c
|
||||||
|
*/
|
||||||
|
static int do_standby_disk(int fd)
|
||||||
|
{
|
||||||
|
#ifndef WIN_STANDBYNOW1
|
||||||
|
#define WIN_STANDBYNOW1 0xE0
|
||||||
|
#endif
|
||||||
|
#ifndef WIN_STANDBYNOW2
|
||||||
|
#define WIN_STANDBYNOW2 0x94
|
||||||
|
#endif
|
||||||
|
unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
|
||||||
|
unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
|
||||||
|
ioctl(fd, HDIO_DRIVE_CMD, &args2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put all specified disks in standby mode.
|
||||||
|
*/
|
||||||
|
static int do_standby_disks(const int *fds, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
do_standby_disk(fds[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First find all IDE/SCSI/SATA disks, then put them in standby mode.
|
||||||
|
* This has the side-effect of flushing the writecache,
|
||||||
|
* which is exactly what we want on poweroff.
|
||||||
|
*/
|
||||||
|
int hddown(void)
|
||||||
|
{
|
||||||
|
const char *disks[MAX_DISKS];
|
||||||
|
int fds[MAX_DISKS];
|
||||||
|
int count = 0;
|
||||||
|
int result1, result2;
|
||||||
|
|
||||||
|
result1 = find_idedisks(disks, MAX_DISKS, &count);
|
||||||
|
result2 = find_scsidisks(disks, MAX_DISKS, &count);
|
||||||
|
|
||||||
|
open_disks(disks, fds, count);
|
||||||
|
do_standby_disks(fds, count);
|
||||||
|
|
||||||
|
return (result1 ? result1 : result2);
|
||||||
|
}
|
||||||
|
#endif /* ! USE_SYSFS */
|
||||||
|
#else /* __linux__ */
|
||||||
|
|
||||||
|
int hddown(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
return (hddown() == 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
91
src/ifdown.c
Normal file
91
src/ifdown.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* ifdown.c Find all network interfaces on the system and
|
||||||
|
* shut them down.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
char *v_ifdown = "@(#)ifdown.c 1.11 02-Jun-1998 miquels@cistron.nl";
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#define MAX_IFS 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, we find all shaper devices and down them. Then we
|
||||||
|
* down all real interfaces. This is because the comment in the
|
||||||
|
* shaper driver says "if you down the shaper device before the
|
||||||
|
* attached inerface your computer will follow".
|
||||||
|
*/
|
||||||
|
int ifdown(void)
|
||||||
|
{
|
||||||
|
struct ifreq ifr[MAX_IFS];
|
||||||
|
struct ifconf ifc;
|
||||||
|
int i, fd;
|
||||||
|
int numif;
|
||||||
|
int shaper;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
|
fprintf(stderr, "ifdown: ");
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ifc.ifc_len = sizeof(ifr);
|
||||||
|
ifc.ifc_req = ifr;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
|
||||||
|
fprintf(stderr, "ifdown: ");
|
||||||
|
perror("SIOCGIFCONF");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
numif = ifc.ifc_len / sizeof(struct ifreq);
|
||||||
|
|
||||||
|
for (shaper = 1; shaper >= 0; shaper--) {
|
||||||
|
for (i = 0; i < numif; i++) {
|
||||||
|
|
||||||
|
if ((strncmp(ifr[i].ifr_name, "shaper", 6) == 0)
|
||||||
|
!= shaper) continue;
|
||||||
|
|
||||||
|
if (strcmp(ifr[i].ifr_name, "lo") == 0)
|
||||||
|
continue;
|
||||||
|
if (strchr(ifr[i].ifr_name, ':') != NULL)
|
||||||
|
continue;
|
||||||
|
ifr[i].ifr_flags &= ~(IFF_UP);
|
||||||
|
if (ioctl(fd, SIOCSIFFLAGS, &ifr[i]) < 0) {
|
||||||
|
fprintf(stderr, "ifdown: shutdown ");
|
||||||
|
perror(ifr[i].ifr_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
2714
src/init.c
Normal file
2714
src/init.c
Normal file
File diff suppressed because it is too large
Load Diff
139
src/init.h
Normal file
139
src/init.h
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* init.h Several defines and declarations to be
|
||||||
|
* included by all modules of the init program.
|
||||||
|
*
|
||||||
|
* Version: @(#)init.h 2.85-5 02-Jul-2003 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Standard configuration */
|
||||||
|
#define CHANGE_WAIT 0 /* Change runlevel while
|
||||||
|
waiting for a process to exit? */
|
||||||
|
/* Debug and test modes */
|
||||||
|
#define DEBUG 0 /* Debug code off */
|
||||||
|
#define INITDEBUG 0 /* Fork at startup to debug init. */
|
||||||
|
|
||||||
|
/* Some constants */
|
||||||
|
#define INITPID 1 /* pid of first process */
|
||||||
|
#define PIPE_FD 10 /* Fileno of initfifo. */
|
||||||
|
#define STATE_PIPE 11 /* used to pass state through exec */
|
||||||
|
|
||||||
|
/* Failsafe configuration */
|
||||||
|
#define MAXSPAWN 10 /* Max times respawned in.. */
|
||||||
|
#define TESTTIME 120 /* this much seconds */
|
||||||
|
#define SLEEPTIME 300 /* Disable time */
|
||||||
|
|
||||||
|
/* Default path inherited by every child. */
|
||||||
|
#define PATH_DEFAULT "/sbin:/usr/sbin:/bin:/usr/bin"
|
||||||
|
|
||||||
|
|
||||||
|
/* Prototypes. */
|
||||||
|
void write_utmp_wtmp(char *user, char *id, int pid, int type, char *line);
|
||||||
|
void write_wtmp(char *user, char *id, int pid, int type, char *line);
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
void initlog(int loglevel, char *fmt, ...);
|
||||||
|
void set_term(int how);
|
||||||
|
void print(char *fmt);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
# define INITDBG(level, fmt, args...) initlog(level, fmt, ##args)
|
||||||
|
#else
|
||||||
|
# define INITDBG(level, fmt, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Actions to be taken by init */
|
||||||
|
#define RESPAWN 1
|
||||||
|
#define WAIT 2
|
||||||
|
#define ONCE 3
|
||||||
|
#define BOOT 4
|
||||||
|
#define BOOTWAIT 5
|
||||||
|
#define POWERFAIL 6
|
||||||
|
#define POWERWAIT 7
|
||||||
|
#define POWEROKWAIT 8
|
||||||
|
#define CTRLALTDEL 9
|
||||||
|
#define OFF 10
|
||||||
|
#define ONDEMAND 11
|
||||||
|
#define INITDEFAULT 12
|
||||||
|
#define SYSINIT 13
|
||||||
|
#define POWERFAILNOW 14
|
||||||
|
#define KBREQUEST 15
|
||||||
|
|
||||||
|
/* Information about a process in the in-core inittab */
|
||||||
|
typedef struct _child_ {
|
||||||
|
int flags; /* Status of this entry */
|
||||||
|
int exstat; /* Exit status of process */
|
||||||
|
int pid; /* Pid of this process */
|
||||||
|
time_t tm; /* When respawned last */
|
||||||
|
int count; /* Times respawned in the last 2 minutes */
|
||||||
|
char id[8]; /* Inittab id (must be unique) */
|
||||||
|
char rlevel[12]; /* run levels */
|
||||||
|
int action; /* what to do (see list below) */
|
||||||
|
char process[128]; /* The command line */
|
||||||
|
struct _child_ *new; /* New entry (after inittab re-read) */
|
||||||
|
struct _child_ *next; /* For the linked list */
|
||||||
|
} CHILD;
|
||||||
|
|
||||||
|
/* Values for the 'flags' field */
|
||||||
|
#define RUNNING 2 /* Process is still running */
|
||||||
|
#define KILLME 4 /* Kill this process */
|
||||||
|
#define DEMAND 8 /* "runlevels" a b c */
|
||||||
|
#define FAILING 16 /* process respawns rapidly */
|
||||||
|
#define WAITING 32 /* We're waiting for this process */
|
||||||
|
#define ZOMBIE 64 /* This process is already dead */
|
||||||
|
#define XECUTED 128 /* Set if spawned once or more times */
|
||||||
|
|
||||||
|
/* Log levels. */
|
||||||
|
#define L_CO 1 /* Log on the console. */
|
||||||
|
#define L_SY 2 /* Log with syslog() */
|
||||||
|
#define L_VB (L_CO|L_SY) /* Log with both. */
|
||||||
|
|
||||||
|
#ifndef NO_PROCESS
|
||||||
|
# define NO_PROCESS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global variables.
|
||||||
|
*/
|
||||||
|
extern CHILD *family;
|
||||||
|
extern int wrote_wtmp_reboot;
|
||||||
|
extern int wrote_utmp_reboot;
|
||||||
|
|
||||||
|
/* Tokens in state parser */
|
||||||
|
#define C_VER 1
|
||||||
|
#define C_END 2
|
||||||
|
#define C_REC 3
|
||||||
|
#define C_EOR 4
|
||||||
|
#define C_LEV 5
|
||||||
|
#define C_FLAG 6
|
||||||
|
#define C_ACTION 7
|
||||||
|
#define C_PROCESS 8
|
||||||
|
#define C_PID 9
|
||||||
|
#define C_EXS 10
|
||||||
|
#define C_EOF -1
|
||||||
|
#define D_RUNLEVEL -2
|
||||||
|
#define D_THISLEVEL -3
|
||||||
|
#define D_PREVLEVEL -4
|
||||||
|
#define D_GOTSIGN -5
|
||||||
|
#define D_WROTE_WTMP_REBOOT -6
|
||||||
|
#define D_WROTE_UTMP_REBOOT -7
|
||||||
|
#define D_SLTIME -8
|
||||||
|
#define D_DIDBOOT -9
|
||||||
|
|
86
src/initreq.h
Normal file
86
src/initreq.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* initreq.h Interface to talk to init through /dev/initctl.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995-2004 Miquel van Smoorenburg
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Version: @(#)initreq.h 1.28 31-Mar-2004 MvS
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef _INITREQ_H
|
||||||
|
#define _INITREQ_H
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD_kernel__)
|
||||||
|
# define INIT_FIFO "/etc/.initctl"
|
||||||
|
#else
|
||||||
|
# define INIT_FIFO "/dev/initctl"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INIT_MAGIC 0x03091969
|
||||||
|
#define INIT_CMD_START 0
|
||||||
|
#define INIT_CMD_RUNLVL 1
|
||||||
|
#define INIT_CMD_POWERFAIL 2
|
||||||
|
#define INIT_CMD_POWERFAILNOW 3
|
||||||
|
#define INIT_CMD_POWEROK 4
|
||||||
|
#define INIT_CMD_BSD 5
|
||||||
|
#define INIT_CMD_SETENV 6
|
||||||
|
#define INIT_CMD_UNSETENV 7
|
||||||
|
|
||||||
|
#define INIT_CMD_CHANGECONS 12345
|
||||||
|
|
||||||
|
#ifdef MAXHOSTNAMELEN
|
||||||
|
# define INITRQ_HLEN MAXHOSTNAMELEN
|
||||||
|
#else
|
||||||
|
# define INITRQ_HLEN 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is what BSD 4.4 uses when talking to init.
|
||||||
|
* Linux doesn't use this right now.
|
||||||
|
*/
|
||||||
|
struct init_request_bsd {
|
||||||
|
char gen_id[8]; /* Beats me.. telnetd uses "fe" */
|
||||||
|
char tty_id[16]; /* Tty name minus /dev/tty */
|
||||||
|
char host[INITRQ_HLEN]; /* Hostname */
|
||||||
|
char term_type[16]; /* Terminal type */
|
||||||
|
int signal; /* Signal to send */
|
||||||
|
int pid; /* Process to send to */
|
||||||
|
char exec_name[128]; /* Program to execute */
|
||||||
|
char reserved[128]; /* For future expansion. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because of legacy interfaces, "runlevel" and "sleeptime"
|
||||||
|
* aren't in a seperate struct in the union.
|
||||||
|
*
|
||||||
|
* The weird sizes are because init expects the whole
|
||||||
|
* struct to be 384 bytes.
|
||||||
|
*/
|
||||||
|
struct init_request {
|
||||||
|
int magic; /* Magic number */
|
||||||
|
int cmd; /* What kind of request */
|
||||||
|
int runlevel; /* Runlevel to change to */
|
||||||
|
int sleeptime; /* Time between TERM and KILL */
|
||||||
|
union {
|
||||||
|
struct init_request_bsd bsd;
|
||||||
|
char data[368];
|
||||||
|
} i;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
25
src/initscript.sample
Executable file
25
src/initscript.sample
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#
|
||||||
|
# initscript If this script is intalled as /etc/initscript,
|
||||||
|
# it is executed by init(8) for every program it
|
||||||
|
# wants to spawn like this:
|
||||||
|
#
|
||||||
|
# /bin/sh /etc/initscript <id> <level> <action> <process>
|
||||||
|
#
|
||||||
|
# It can be used to set the default umask and ulimit
|
||||||
|
# of all processes. By default this script is installed
|
||||||
|
# as /etc/initscript.sample, so to enable it you must
|
||||||
|
# rename this script first to /etc/initscript.
|
||||||
|
#
|
||||||
|
# Version: @(#)initscript 1.10 10-Dec-1995 MvS.
|
||||||
|
#
|
||||||
|
# Author: Miquel van Smoorenburg, <miquels@cistron.nl>
|
||||||
|
#
|
||||||
|
|
||||||
|
# Set umask to safe level, and enable core dumps.
|
||||||
|
umask 022
|
||||||
|
ulimit -c 2097151
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
# Execute the program.
|
||||||
|
eval exec "$4"
|
741
src/killall5.c
Normal file
741
src/killall5.c
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
/*
|
||||||
|
* kilall5.c Kill all processes except processes that have the
|
||||||
|
* same session id, so that the shell that called us
|
||||||
|
* won't be killed. Typically used in shutdown scripts.
|
||||||
|
*
|
||||||
|
* pidof.c Tries to get the pid of the process[es] named.
|
||||||
|
*
|
||||||
|
* Version: 2.86 30-Jul-2004 MvS
|
||||||
|
*
|
||||||
|
* Usage: killall5 [-][signal]
|
||||||
|
* pidof [-s] [-o omitpid [-o omitpid]] program [program..]
|
||||||
|
*
|
||||||
|
* Authors: Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Riku Meskanen, <mesrik@jyu.fi>
|
||||||
|
* - return all running pids of given program name
|
||||||
|
* - single shot '-s' option for backwards combatibility
|
||||||
|
* - omit pid '-o' option and %PPID (parent pid metavariable)
|
||||||
|
* - syslog() only if not a connected to controlling terminal
|
||||||
|
* - swapped out programs pids are caught now
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
|
||||||
|
|
||||||
|
#define STATNAMELEN 15
|
||||||
|
#define DO_STAT 1
|
||||||
|
#define NO_STAT 0
|
||||||
|
|
||||||
|
/* Info about a process. */
|
||||||
|
typedef struct proc {
|
||||||
|
char *argv0; /* Name as found out from argv[0] */
|
||||||
|
char *argv0base; /* `basename argv[1]` */
|
||||||
|
char *argv1; /* Name as found out from argv[1] */
|
||||||
|
char *argv1base; /* `basename argv[1]` */
|
||||||
|
char *statname; /* the statname without braces */
|
||||||
|
ino_t ino; /* Inode number */
|
||||||
|
dev_t dev; /* Device it is on */
|
||||||
|
pid_t pid; /* Process ID. */
|
||||||
|
int sid; /* Session ID. */
|
||||||
|
int kernel; /* Kernel thread or zombie. */
|
||||||
|
struct proc *next; /* Pointer to next struct. */
|
||||||
|
} PROC;
|
||||||
|
|
||||||
|
/* pid queue */
|
||||||
|
|
||||||
|
typedef struct pidq {
|
||||||
|
PROC *proc;
|
||||||
|
struct pidq *next;
|
||||||
|
} PIDQ;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PIDQ *head;
|
||||||
|
PIDQ *tail;
|
||||||
|
PIDQ *next;
|
||||||
|
} PIDQ_HEAD;
|
||||||
|
|
||||||
|
/* List of processes. */
|
||||||
|
PROC *plist;
|
||||||
|
|
||||||
|
/* Did we stop all processes ? */
|
||||||
|
int sent_sigstop;
|
||||||
|
|
||||||
|
int scripts_too = 0;
|
||||||
|
|
||||||
|
char *progname; /* the name of the running program */
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
void nsyslog(int pri, char *fmt, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Malloc space, barf if out of memory.
|
||||||
|
*/
|
||||||
|
void *xmalloc(int bytes)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = malloc(bytes)) == NULL) {
|
||||||
|
if (sent_sigstop) kill(-1, SIGCONT);
|
||||||
|
nsyslog(LOG_ERR, "out of memory");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if the proc filesystem is there. Mount if needed.
|
||||||
|
*/
|
||||||
|
int mount_proc(void)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char *args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
|
||||||
|
pid_t pid, rc;
|
||||||
|
int wst;
|
||||||
|
int did_mount = 0;
|
||||||
|
|
||||||
|
/* Stat /proc/version to see if /proc is mounted. */
|
||||||
|
if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
|
||||||
|
|
||||||
|
/* It's not there, so mount it. */
|
||||||
|
if ((pid = fork()) < 0) {
|
||||||
|
nsyslog(LOG_ERR, "cannot fork");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
/* Try a few mount binaries. */
|
||||||
|
execv("/sbin/mount", args);
|
||||||
|
execv("/bin/mount", args);
|
||||||
|
|
||||||
|
/* Okay, I give up. */
|
||||||
|
nsyslog(LOG_ERR, "cannot execute mount");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* Wait for child. */
|
||||||
|
while ((rc = wait(&wst)) != pid)
|
||||||
|
if (rc < 0 && errno == ECHILD)
|
||||||
|
break;
|
||||||
|
if (rc != pid || WEXITSTATUS(wst) != 0)
|
||||||
|
nsyslog(LOG_ERR, "mount returned non-zero exit status");
|
||||||
|
|
||||||
|
did_mount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if mount succeeded. */
|
||||||
|
if (stat("/proc/version", &st) < 0) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
|
||||||
|
else
|
||||||
|
nsyslog(LOG_ERR, "/proc unavailable.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return did_mount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readarg(FILE *fp, char *buf, int sz)
|
||||||
|
{
|
||||||
|
int c = 0, f = 0;
|
||||||
|
|
||||||
|
while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
|
||||||
|
buf[f++] = c;
|
||||||
|
buf[f] = 0;
|
||||||
|
|
||||||
|
return (c == EOF && f == 0) ? c : f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the proc filesystem.
|
||||||
|
* CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
|
||||||
|
*/
|
||||||
|
int readproc(int do_stat)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
FILE *fp;
|
||||||
|
PROC *p, *n;
|
||||||
|
struct dirent *d;
|
||||||
|
struct stat st;
|
||||||
|
char path[256];
|
||||||
|
char buf[256];
|
||||||
|
char *s, *q;
|
||||||
|
unsigned long startcode, endcode;
|
||||||
|
int pid, f;
|
||||||
|
|
||||||
|
/* Open the /proc directory. */
|
||||||
|
if (chdir("/proc") == -1) {
|
||||||
|
nsyslog(LOG_ERR, "chdir /proc failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((dir = opendir(".")) == NULL) {
|
||||||
|
nsyslog(LOG_ERR, "cannot opendir(/proc)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the already existing process list. */
|
||||||
|
n = plist;
|
||||||
|
for (p = plist; n; p = n) {
|
||||||
|
n = p->next;
|
||||||
|
if (p->argv0) free(p->argv0);
|
||||||
|
if (p->argv1) free(p->argv1);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
plist = NULL;
|
||||||
|
|
||||||
|
/* Walk through the directory. */
|
||||||
|
while ((d = readdir(dir)) != NULL) {
|
||||||
|
|
||||||
|
/* See if this is a process */
|
||||||
|
if ((pid = atoi(d->d_name)) == 0) continue;
|
||||||
|
|
||||||
|
/* Get a PROC struct . */
|
||||||
|
p = (PROC *)xmalloc(sizeof(PROC));
|
||||||
|
memset(p, 0, sizeof(PROC));
|
||||||
|
|
||||||
|
/* Open the status file. */
|
||||||
|
snprintf(path, sizeof(path), "%s/stat", d->d_name);
|
||||||
|
|
||||||
|
/* Read SID & statname from it. */
|
||||||
|
if ((fp = fopen(path, "r")) != NULL) {
|
||||||
|
buf[0] = 0;
|
||||||
|
fgets(buf, sizeof(buf), fp);
|
||||||
|
|
||||||
|
/* See if name starts with '(' */
|
||||||
|
s = buf;
|
||||||
|
while (*s != ' ') s++;
|
||||||
|
s++;
|
||||||
|
if (*s == '(') {
|
||||||
|
/* Read program name. */
|
||||||
|
q = strrchr(buf, ')');
|
||||||
|
if (q == NULL) {
|
||||||
|
p->sid = 0;
|
||||||
|
nsyslog(LOG_ERR,
|
||||||
|
"can't get program name from /proc/%s\n",
|
||||||
|
path);
|
||||||
|
free(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
q = s;
|
||||||
|
while (*q != ' ') q++;
|
||||||
|
}
|
||||||
|
*q++ = 0;
|
||||||
|
while (*q == ' ') q++;
|
||||||
|
p->statname = (char *)xmalloc(strlen(s)+1);
|
||||||
|
strcpy(p->statname, s);
|
||||||
|
|
||||||
|
/* Get session, startcode, endcode. */
|
||||||
|
startcode = endcode = 0;
|
||||||
|
if (sscanf(q, "%*c %*d %*d %d %*d %*d %*u %*u "
|
||||||
|
"%*u %*u %*u %*u %*u %*d %*d "
|
||||||
|
"%*d %*d %*d %*d %*u %*u %*d "
|
||||||
|
"%*u %lu %lu",
|
||||||
|
&p->sid, &startcode, &endcode) != 3) {
|
||||||
|
p->sid = 0;
|
||||||
|
nsyslog(LOG_ERR, "can't read sid from %s\n",
|
||||||
|
path);
|
||||||
|
free(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (startcode == 0 && endcode == 0)
|
||||||
|
p->kernel = 1;
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
/* Process disappeared.. */
|
||||||
|
free(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/cmdline", d->d_name);
|
||||||
|
if ((fp = fopen(path, "r")) != NULL) {
|
||||||
|
|
||||||
|
/* Now read argv[0] */
|
||||||
|
f = readarg(fp, buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (buf[0]) {
|
||||||
|
/* Store the name into malloced memory. */
|
||||||
|
p->argv0 = (char *)xmalloc(f + 1);
|
||||||
|
strcpy(p->argv0, buf);
|
||||||
|
|
||||||
|
/* Get a pointer to the basename. */
|
||||||
|
p->argv0base = strrchr(p->argv0, '/');
|
||||||
|
if (p->argv0base != NULL)
|
||||||
|
p->argv0base++;
|
||||||
|
else
|
||||||
|
p->argv0base = p->argv0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And read argv[1] */
|
||||||
|
while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
|
||||||
|
if (buf[0] != '-') break;
|
||||||
|
|
||||||
|
if (buf[0]) {
|
||||||
|
/* Store the name into malloced memory. */
|
||||||
|
p->argv1 = (char *)xmalloc(f + 1);
|
||||||
|
strcpy(p->argv1, buf);
|
||||||
|
|
||||||
|
/* Get a pointer to the basename. */
|
||||||
|
p->argv1base = strrchr(p->argv1, '/');
|
||||||
|
if (p->argv1base != NULL)
|
||||||
|
p->argv1base++;
|
||||||
|
else
|
||||||
|
p->argv1base = p->argv1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Process disappeared.. */
|
||||||
|
free(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to stat the executable. */
|
||||||
|
snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
|
||||||
|
if (do_stat && stat(path, &st) == 0) {
|
||||||
|
p->dev = st.st_dev;
|
||||||
|
p->ino = st.st_ino;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link it into the list. */
|
||||||
|
p->next = plist;
|
||||||
|
plist = p;
|
||||||
|
p->pid = pid;
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
/* Done. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
|
||||||
|
{
|
||||||
|
q->head = q->next = q->tail = NULL;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
int empty_q(PIDQ_HEAD *q)
|
||||||
|
{
|
||||||
|
return (q->head == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
|
||||||
|
{
|
||||||
|
PIDQ *tmp;
|
||||||
|
|
||||||
|
tmp = (PIDQ *)xmalloc(sizeof(PIDQ));
|
||||||
|
|
||||||
|
tmp->proc = p;
|
||||||
|
tmp->next = NULL;
|
||||||
|
|
||||||
|
if (empty_q(q)) {
|
||||||
|
q->head = tmp;
|
||||||
|
q->tail = tmp;
|
||||||
|
} else {
|
||||||
|
q->tail->next = tmp;
|
||||||
|
q->tail = tmp;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC *get_next_from_pid_q(PIDQ_HEAD *q)
|
||||||
|
{
|
||||||
|
PROC *p;
|
||||||
|
PIDQ *tmp = q->head;
|
||||||
|
|
||||||
|
if (!empty_q(q)) {
|
||||||
|
p = q->head->proc;
|
||||||
|
q->head = tmp->next;
|
||||||
|
free(tmp);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to get the process ID of a given process. */
|
||||||
|
PIDQ_HEAD *pidof(char *prog)
|
||||||
|
{
|
||||||
|
PROC *p;
|
||||||
|
PIDQ_HEAD *q;
|
||||||
|
struct stat st;
|
||||||
|
char *s;
|
||||||
|
int dostat = 0;
|
||||||
|
int foundone = 0;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
if (! prog)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Get basename of program. */
|
||||||
|
if ((s = strrchr(prog, '/')) == NULL)
|
||||||
|
s = prog;
|
||||||
|
else
|
||||||
|
s++;
|
||||||
|
|
||||||
|
if (! *s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
|
||||||
|
q = init_pid_q(q);
|
||||||
|
|
||||||
|
/* Try to stat the executable. */
|
||||||
|
if (prog[0] == '/' && stat(prog, &st) == 0)
|
||||||
|
dostat++;
|
||||||
|
|
||||||
|
/* First try to find a match based on dev/ino pair. */
|
||||||
|
if (dostat) {
|
||||||
|
for (p = plist; p; p = p->next) {
|
||||||
|
if (p->dev == st.st_dev && p->ino == st.st_ino) {
|
||||||
|
add_pid_to_q(q, p);
|
||||||
|
foundone++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't find a match based on dev/ino, try the name. */
|
||||||
|
if (!foundone) for (p = plist; p; p = p->next) {
|
||||||
|
ok = 0;
|
||||||
|
|
||||||
|
/* matching nonmatching
|
||||||
|
* proc name prog name prog name
|
||||||
|
* --- ----------- ------------
|
||||||
|
* b b, p/b, q/b
|
||||||
|
* p/b b, p/b q/b
|
||||||
|
*
|
||||||
|
* Algorithm: Match if:
|
||||||
|
* cmd = arg
|
||||||
|
* or cmd = base(arg)
|
||||||
|
* or base(cmd) = arg
|
||||||
|
*
|
||||||
|
* Specifically, do not match just because base(cmd) = base(arg)
|
||||||
|
* as was done in earlier versions of this program, since this
|
||||||
|
* allows /aaa/foo to match /bbb/foo .
|
||||||
|
*/
|
||||||
|
ok |=
|
||||||
|
(p->argv0 && strcmp(p->argv0, prog) == 0)
|
||||||
|
|| (p->argv0 && s != prog && strcmp(p->argv0, s) == 0)
|
||||||
|
|| (p->argv0base && strcmp(p->argv0base, prog) == 0);
|
||||||
|
|
||||||
|
/* For scripts, compare argv[1] as well. */
|
||||||
|
if (
|
||||||
|
scripts_too && p->statname && p->argv1base
|
||||||
|
&& !strncmp(p->statname, p->argv1base, STATNAMELEN)
|
||||||
|
) {
|
||||||
|
ok |=
|
||||||
|
(p->argv1 && strcmp(p->argv1, prog) == 0)
|
||||||
|
|| (p->argv1 && s != prog && strcmp(p->argv1, s) == 0)
|
||||||
|
|| (p->argv1base && strcmp(p->argv1base, prog) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we have a space in argv0, process probably
|
||||||
|
* used setproctitle so try statname.
|
||||||
|
*/
|
||||||
|
if (strlen(s) <= STATNAMELEN &&
|
||||||
|
(p->argv0 == NULL ||
|
||||||
|
p->argv0[0] == 0 ||
|
||||||
|
strchr(p->argv0, ' '))) {
|
||||||
|
ok |= (strcmp(p->statname, s) == 0);
|
||||||
|
}
|
||||||
|
if (ok) add_pid_to_q(q, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give usage message and exit. */
|
||||||
|
void usage(void)
|
||||||
|
{
|
||||||
|
nsyslog(LOG_ERR, "only one argument, a signal number, allowed");
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write to syslog file if not open terminal */
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
void nsyslog(int pri, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
if (ttyname(0) == NULL) {
|
||||||
|
vsyslog(pri, fmt, args);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: ",progname);
|
||||||
|
vfprintf(stderr, fmt, args);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PIDOF_SINGLE 0x01
|
||||||
|
#define PIDOF_OMIT 0x02
|
||||||
|
|
||||||
|
#define PIDOF_OMITSZ 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pidof functionality.
|
||||||
|
*/
|
||||||
|
int main_pidof(int argc, char **argv)
|
||||||
|
{
|
||||||
|
PIDQ_HEAD *q;
|
||||||
|
PROC *p;
|
||||||
|
pid_t opid[PIDOF_OMITSZ], spid;
|
||||||
|
int f;
|
||||||
|
int first = 1;
|
||||||
|
int i, oind, opt, flags = 0;
|
||||||
|
int chroot_check = 0;
|
||||||
|
struct stat st;
|
||||||
|
char tmp[512];
|
||||||
|
|
||||||
|
for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
|
||||||
|
opid[oind] = 0;
|
||||||
|
opterr = 0;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc,argv,"hco:sx")) != EOF) switch (opt) {
|
||||||
|
case '?':
|
||||||
|
nsyslog(LOG_ERR,"invalid options on command line!\n");
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
case 'c':
|
||||||
|
if (geteuid() == 0) chroot_check = 1;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
if (oind >= PIDOF_OMITSZ -1) {
|
||||||
|
nsyslog(LOG_ERR,"omit pid buffer size %d "
|
||||||
|
"exceeded!\n", PIDOF_OMITSZ);
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (strcmp("%PPID",optarg) == 0)
|
||||||
|
opid[oind] = getppid();
|
||||||
|
else if ((opid[oind] = atoi(optarg)) < 1) {
|
||||||
|
nsyslog(LOG_ERR,
|
||||||
|
"illegal omit pid value (%s)!\n",
|
||||||
|
optarg);
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
oind++;
|
||||||
|
flags |= PIDOF_OMIT;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
flags |= PIDOF_SINGLE;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
scripts_too++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
/* Check if we are in a chroot */
|
||||||
|
if (chroot_check) {
|
||||||
|
snprintf(tmp, 512, "/proc/%d/root", getpid());
|
||||||
|
if (stat(tmp, &st) < 0) {
|
||||||
|
nsyslog(LOG_ERR, "stat failed for %s!\n", tmp);
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print out process-ID's one by one. */
|
||||||
|
readproc(DO_STAT);
|
||||||
|
for(f = 0; f < argc; f++) {
|
||||||
|
if ((q = pidof(argv[f])) != NULL) {
|
||||||
|
spid = 0;
|
||||||
|
while ((p = get_next_from_pid_q(q))) {
|
||||||
|
if (flags & PIDOF_OMIT) {
|
||||||
|
for (i = 0; i < oind; i++)
|
||||||
|
if (opid[i] == p->pid)
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* On a match, continue with
|
||||||
|
* the for loop above.
|
||||||
|
*/
|
||||||
|
if (i < oind)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flags & PIDOF_SINGLE) {
|
||||||
|
if (spid)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
spid = 1;
|
||||||
|
}
|
||||||
|
if (chroot_check) {
|
||||||
|
struct stat st2;
|
||||||
|
snprintf(tmp, 512, "/proc/%d/root",
|
||||||
|
p->pid);
|
||||||
|
if (stat(tmp, &st2) < 0 ||
|
||||||
|
st.st_dev != st2.st_dev ||
|
||||||
|
st.st_ino != st2.st_ino) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
printf(" ");
|
||||||
|
printf("%d", p->pid);
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
printf("\n");
|
||||||
|
closelog();
|
||||||
|
return(first ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define KILLALL_OMITSZ 16
|
||||||
|
|
||||||
|
/* Main for either killall or pidof. */
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
PROC *p;
|
||||||
|
int pid, sid = -1;
|
||||||
|
pid_t opid[KILLALL_OMITSZ];
|
||||||
|
int i, oind, omit = 0;
|
||||||
|
int sig = SIGKILL;
|
||||||
|
|
||||||
|
/* return non-zero if no process was killed */
|
||||||
|
int retval = 2;
|
||||||
|
|
||||||
|
/* Get program name. */
|
||||||
|
if ((progname = strrchr(argv[0], '/')) == NULL)
|
||||||
|
progname = argv[0];
|
||||||
|
else
|
||||||
|
progname++;
|
||||||
|
|
||||||
|
/* Now connect to syslog. */
|
||||||
|
openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
|
||||||
|
|
||||||
|
/* Were we called as 'pidof' ? */
|
||||||
|
if (strcmp(progname, "pidof") == 0)
|
||||||
|
return main_pidof(argc, argv);
|
||||||
|
|
||||||
|
/* Right, so we are "killall". */
|
||||||
|
for (oind = KILLALL_OMITSZ-1; oind > 0; oind--)
|
||||||
|
opid[oind] = 0;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] == '-') (argv[i])++;
|
||||||
|
if (argv[i][0] == 'o') {
|
||||||
|
if (++i >= argc) usage();
|
||||||
|
if (oind >= KILLALL_OMITSZ -1) {
|
||||||
|
nsyslog(LOG_ERR,"omit pid buffer size "
|
||||||
|
"%d exceeded!\n",
|
||||||
|
KILLALL_OMITSZ);
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((opid[oind] = atoi(argv[i])) < 1) {
|
||||||
|
nsyslog(LOG_ERR,
|
||||||
|
"illegal omit pid value "
|
||||||
|
"(%s)!\n", argv[i]);
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
oind++;
|
||||||
|
omit = 1;
|
||||||
|
}
|
||||||
|
else if ((sig = atoi(argv[1])) <= 0 || sig > 31)
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First get the /proc filesystem online. */
|
||||||
|
mount_proc();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignoring SIGKILL and SIGSTOP do not make sense, but
|
||||||
|
* someday kill(-1, sig) might kill ourself if we don't
|
||||||
|
* do this. This certainly is a valid concern for SIGTERM-
|
||||||
|
* Linux 2.1 might send the calling process the signal too.
|
||||||
|
*/
|
||||||
|
signal(SIGTERM, SIG_IGN);
|
||||||
|
signal(SIGSTOP, SIG_IGN);
|
||||||
|
signal(SIGKILL, SIG_IGN);
|
||||||
|
|
||||||
|
/* lock us into memory */
|
||||||
|
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||||
|
|
||||||
|
/* Now stop all processes. */
|
||||||
|
kill(-1, SIGSTOP);
|
||||||
|
sent_sigstop = 1;
|
||||||
|
|
||||||
|
/* Read /proc filesystem */
|
||||||
|
if (readproc(NO_STAT) < 0) {
|
||||||
|
kill(-1, SIGCONT);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now kill all processes except init (pid 1) and our session. */
|
||||||
|
sid = (int)getsid(0);
|
||||||
|
pid = (int)getpid();
|
||||||
|
for (p = plist; p; p = p->next) {
|
||||||
|
if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel)
|
||||||
|
continue;
|
||||||
|
if (omit) {
|
||||||
|
for (i = 0; i < oind; i++)
|
||||||
|
if (opid[i] == p->pid)
|
||||||
|
break;
|
||||||
|
/* On a match, continue with the for loop above. */
|
||||||
|
if (i < oind)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kill(p->pid, sig);
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And let them continue. */
|
||||||
|
kill(-1, SIGCONT);
|
||||||
|
|
||||||
|
/* Done. */
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
/* Force the kernel to run the scheduler */
|
||||||
|
usleep(1);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
911
src/last.c
Normal file
911
src/last.c
Normal file
@ -0,0 +1,911 @@
|
|||||||
|
/*
|
||||||
|
* last.c Re-implementation of the 'last' command, this time
|
||||||
|
* for Linux. Yes I know there is BSD last, but I
|
||||||
|
* just felt like writing this. No thanks :-).
|
||||||
|
* Also, this version gives lots more info (especially with -x)
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Version: @(#)last 2.85 30-Jul-2004 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "oldutmp.h"
|
||||||
|
|
||||||
|
#ifndef SHUTDOWN_TIME
|
||||||
|
# define SHUTDOWN_TIME 254
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *Version = "@(#) last 2.85 31-Apr-2004 miquels";
|
||||||
|
|
||||||
|
#define CHOP_DOMAIN 0 /* Define to chop off local domainname. */
|
||||||
|
#define NEW_UTMP 1 /* Fancy & fast utmp read code. */
|
||||||
|
#define UCHUNKSIZE 16384 /* How much we read at once. */
|
||||||
|
|
||||||
|
/* Double linked list of struct utmp's */
|
||||||
|
struct utmplist {
|
||||||
|
struct utmp ut;
|
||||||
|
struct utmplist *next;
|
||||||
|
struct utmplist *prev;
|
||||||
|
};
|
||||||
|
struct utmplist *utmplist = NULL;
|
||||||
|
|
||||||
|
/* Types of listing */
|
||||||
|
#define R_CRASH 1 /* No logout record, system boot in between */
|
||||||
|
#define R_DOWN 2 /* System brought down in decent way */
|
||||||
|
#define R_NORMAL 3 /* Normal */
|
||||||
|
#define R_NOW 4 /* Still logged in */
|
||||||
|
#define R_REBOOT 5 /* Reboot record. */
|
||||||
|
#define R_PHANTOM 6 /* No logout record but session is stale. */
|
||||||
|
#define R_TIMECHANGE 7 /* NEW_TIME or OLD_TIME */
|
||||||
|
|
||||||
|
/* Global variables */
|
||||||
|
int maxrecs = 0; /* Maximum number of records to list. */
|
||||||
|
int recsdone = 0; /* Number of records listed */
|
||||||
|
int showhost = 1; /* Show hostname too? */
|
||||||
|
int altlist = 0; /* Show hostname at the end. */
|
||||||
|
int usedns = 0; /* Use DNS to lookup the hostname. */
|
||||||
|
int useip = 0; /* Print IP address in number format */
|
||||||
|
int fulltime = 0; /* Print full dates and times */
|
||||||
|
int oldfmt = 0; /* Use old libc5 format? */
|
||||||
|
char **show = NULL; /* What do they want us to show */
|
||||||
|
char *ufile; /* Filename of this file */
|
||||||
|
time_t lastdate; /* Last date we've seen */
|
||||||
|
char *progname; /* Name of this program */
|
||||||
|
#if CHOP_DOMAIN
|
||||||
|
char hostname[256]; /* For gethostbyname() */
|
||||||
|
char *domainname; /* Our domainname. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert old utmp format to new.
|
||||||
|
*/
|
||||||
|
void uconv(struct oldutmp *oldut, struct utmp *utn)
|
||||||
|
{
|
||||||
|
memset(utn, 0, sizeof(struct utmp));
|
||||||
|
utn->ut_type = oldut->ut_type;
|
||||||
|
utn->ut_pid = oldut->ut_pid;
|
||||||
|
utn->ut_time = oldut->ut_oldtime;
|
||||||
|
utn->ut_addr = oldut->ut_oldaddr;
|
||||||
|
strncpy(utn->ut_line, oldut->ut_line, OLD_LINESIZE);
|
||||||
|
strncpy(utn->ut_user, oldut->ut_user, OLD_NAMESIZE);
|
||||||
|
strncpy(utn->ut_host, oldut->ut_host, OLD_HOSTSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NEW_UTMP
|
||||||
|
/*
|
||||||
|
* Read one utmp entry, return in new format.
|
||||||
|
* Automatically reposition file pointer.
|
||||||
|
*/
|
||||||
|
int uread(FILE *fp, struct utmp *u, int *quit)
|
||||||
|
{
|
||||||
|
static int utsize;
|
||||||
|
static char buf[UCHUNKSIZE];
|
||||||
|
char tmp[1024];
|
||||||
|
static off_t fpos;
|
||||||
|
static int bpos;
|
||||||
|
struct oldutmp uto;
|
||||||
|
int r;
|
||||||
|
off_t o;
|
||||||
|
|
||||||
|
if (quit == NULL && u != NULL) {
|
||||||
|
/*
|
||||||
|
* Normal read.
|
||||||
|
*/
|
||||||
|
if (oldfmt) {
|
||||||
|
r = fread(&uto, sizeof(uto), 1, fp);
|
||||||
|
uconv(&uto, u);
|
||||||
|
} else
|
||||||
|
r = fread(u, sizeof(struct utmp), 1, fp);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u == NULL) {
|
||||||
|
/*
|
||||||
|
* Initialize and position.
|
||||||
|
*/
|
||||||
|
utsize = oldfmt ? sizeof(uto) : sizeof(struct utmp);
|
||||||
|
fseeko(fp, 0, SEEK_END);
|
||||||
|
fpos = ftello(fp);
|
||||||
|
if (fpos == 0)
|
||||||
|
return 0;
|
||||||
|
o = ((fpos - 1) / UCHUNKSIZE) * UCHUNKSIZE;
|
||||||
|
if (fseeko(fp, o, SEEK_SET) < 0) {
|
||||||
|
fprintf(stderr, "%s: seek failed!\n", progname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bpos = (int)(fpos - o);
|
||||||
|
if (fread(buf, bpos, 1, fp) != 1) {
|
||||||
|
fprintf(stderr, "%s: read failed!\n", progname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fpos = o;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read one struct. From the buffer if possible.
|
||||||
|
*/
|
||||||
|
bpos -= utsize;
|
||||||
|
if (bpos >= 0) {
|
||||||
|
if (oldfmt)
|
||||||
|
uconv((struct oldutmp *)(buf + bpos), u);
|
||||||
|
else
|
||||||
|
memcpy(u, buf + bpos, sizeof(struct utmp));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Oops we went "below" the buffer. We should be able to
|
||||||
|
* seek back UCHUNKSIZE bytes.
|
||||||
|
*/
|
||||||
|
fpos -= UCHUNKSIZE;
|
||||||
|
if (fpos < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy whatever is left in the buffer.
|
||||||
|
*/
|
||||||
|
memcpy(tmp + (-bpos), buf, utsize + bpos);
|
||||||
|
if (fseeko(fp, fpos, SEEK_SET) < 0) {
|
||||||
|
perror("fseek");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read another UCHUNKSIZE bytes.
|
||||||
|
*/
|
||||||
|
if (fread(buf, UCHUNKSIZE, 1, fp) != 1) {
|
||||||
|
perror("fread");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The end of the UCHUNKSIZE byte buffer should be the first
|
||||||
|
* few bytes of the current struct utmp.
|
||||||
|
*/
|
||||||
|
memcpy(tmp, buf + UCHUNKSIZE + bpos, -bpos);
|
||||||
|
bpos += UCHUNKSIZE;
|
||||||
|
|
||||||
|
if (oldfmt)
|
||||||
|
uconv((struct oldutmp *)tmp, u);
|
||||||
|
else
|
||||||
|
memcpy(u, tmp, sizeof(struct utmp));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* NEW_UTMP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read one utmp entry, return in new format.
|
||||||
|
* Automatically reposition file pointer.
|
||||||
|
*/
|
||||||
|
int uread(FILE *fp, struct utmp *u, int *quit)
|
||||||
|
{
|
||||||
|
struct oldutmp uto;
|
||||||
|
off_t r;
|
||||||
|
|
||||||
|
if (u == NULL) {
|
||||||
|
r = oldfmt ? sizeof(struct oldutmp) : sizeof(struct utmp);
|
||||||
|
fseek(fp, -1 * r, SEEK_END);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oldfmt) {
|
||||||
|
r = fread(u, sizeof(struct utmp), 1, fp);
|
||||||
|
if (r == 1) {
|
||||||
|
if (fseeko(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)
|
||||||
|
if (quit) *quit = 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = fread(&uto, sizeof(struct oldutmp), 1, fp);
|
||||||
|
if (r == 1) {
|
||||||
|
if (fseeko(fp, -2 * sizeof(struct oldutmp), SEEK_CUR) < 0)
|
||||||
|
if (quit) *quit = 1;
|
||||||
|
uconv(&uto, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to be smart about the location of the BTMP file
|
||||||
|
*/
|
||||||
|
#ifndef BTMP_FILE
|
||||||
|
#define BTMP_FILE getbtmp()
|
||||||
|
char *getbtmp()
|
||||||
|
{
|
||||||
|
static char btmp[128];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
strcpy(btmp, WTMP_FILE);
|
||||||
|
if ((p = strrchr(btmp, '/')) == NULL)
|
||||||
|
p = btmp;
|
||||||
|
else
|
||||||
|
p++;
|
||||||
|
*p = 0;
|
||||||
|
strcat(btmp, "btmp");
|
||||||
|
return btmp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a short date.
|
||||||
|
*/
|
||||||
|
char *showdate()
|
||||||
|
{
|
||||||
|
char *s = ctime(&lastdate);
|
||||||
|
s[16] = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGINT handler
|
||||||
|
*/
|
||||||
|
void int_handler()
|
||||||
|
{
|
||||||
|
printf("Interrupted %s\n", showdate());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGQUIT handler
|
||||||
|
*/
|
||||||
|
void quit_handler()
|
||||||
|
{
|
||||||
|
printf("Interrupted %s\n", showdate());
|
||||||
|
signal(SIGQUIT, quit_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the basename of a filename
|
||||||
|
*/
|
||||||
|
char *mybasename(char *s)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if ((p = strrchr(s, '/')) != NULL)
|
||||||
|
p++;
|
||||||
|
else
|
||||||
|
p = s;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup a host with DNS.
|
||||||
|
*/
|
||||||
|
int dns_lookup(char *result, int size, int useip, int32_t *a)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
struct sockaddr *sa;
|
||||||
|
int salen, flags;
|
||||||
|
unsigned int topnibble;
|
||||||
|
unsigned int azero = 0, sitelocal = 0;
|
||||||
|
int mapped = 0;
|
||||||
|
|
||||||
|
flags = useip ? NI_NUMERICHOST : 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPv4 or IPv6 ? We use 2 heuristics:
|
||||||
|
* 1. Current IPv6 range uses 2000-3fff or fec0-feff.
|
||||||
|
* Outside of that is illegal and must be IPv4.
|
||||||
|
* 2. If last 3 bytes are 0, must be IPv4
|
||||||
|
* 3. If IPv6 in IPv4, handle as IPv4
|
||||||
|
*
|
||||||
|
* Ugly.
|
||||||
|
*/
|
||||||
|
if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))
|
||||||
|
mapped = 1;
|
||||||
|
topnibble = ntohl((unsigned int)a[0]) >> 28;
|
||||||
|
|
||||||
|
azero = ntohl((unsigned int)a[0]) >> 16;
|
||||||
|
sitelocal = (azero >= 0xfec0 && azero <= 0xfeff) ? 1 : 0;
|
||||||
|
|
||||||
|
if (((topnibble < 2 || topnibble > 3) && (!sitelocal)) || mapped ||
|
||||||
|
(a[1] == 0 && a[2] == 0 && a[3] == 0)) {
|
||||||
|
/* IPv4 */
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = 0;
|
||||||
|
sin.sin_addr.s_addr = mapped ? a[3] : a[0];
|
||||||
|
sa = (struct sockaddr *)&sin;
|
||||||
|
salen = sizeof(sin);
|
||||||
|
} else {
|
||||||
|
/* IPv6 */
|
||||||
|
memset(&sin6, 0, sizeof(sin6));
|
||||||
|
sin6.sin6_family = AF_INET6;
|
||||||
|
sin6.sin6_port = 0;
|
||||||
|
memcpy(sin6.sin6_addr.s6_addr, a, 16);
|
||||||
|
sa = (struct sockaddr *)&sin6;
|
||||||
|
salen = sizeof(sin6);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getnameinfo(sa, salen, result, size, NULL, 0, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show one line of information on screen
|
||||||
|
*/
|
||||||
|
int list(struct utmp *p, time_t t, int what)
|
||||||
|
{
|
||||||
|
time_t secs, tmp;
|
||||||
|
char logintime[32];
|
||||||
|
char logouttime[32];
|
||||||
|
char length[32];
|
||||||
|
char final[128];
|
||||||
|
char utline[UT_LINESIZE+1];
|
||||||
|
char domain[256];
|
||||||
|
char *s, **walk;
|
||||||
|
int mins, hours, days;
|
||||||
|
int r, len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* uucp and ftp have special-type entries
|
||||||
|
*/
|
||||||
|
utline[0] = 0;
|
||||||
|
strncat(utline, p->ut_line, UT_LINESIZE);
|
||||||
|
if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
|
||||||
|
utline[3] = 0;
|
||||||
|
if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
|
||||||
|
utline[4] = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is this something we wanna show?
|
||||||
|
*/
|
||||||
|
if (show) {
|
||||||
|
for (walk = show; *walk; walk++) {
|
||||||
|
if (strncmp(p->ut_name, *walk, UT_NAMESIZE) == 0 ||
|
||||||
|
strcmp(utline, *walk) == 0 ||
|
||||||
|
(strncmp(utline, "tty", 3) == 0 &&
|
||||||
|
strcmp(utline + 3, *walk) == 0)) break;
|
||||||
|
}
|
||||||
|
if (*walk == NULL) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate times
|
||||||
|
*/
|
||||||
|
tmp = (time_t)p->ut_time;
|
||||||
|
strcpy(logintime, ctime(&tmp));
|
||||||
|
if (fulltime)
|
||||||
|
sprintf(logouttime, "- %s", ctime(&t));
|
||||||
|
else {
|
||||||
|
logintime[16] = 0;
|
||||||
|
sprintf(logouttime, "- %s", ctime(&t) + 11);
|
||||||
|
logouttime[7] = 0;
|
||||||
|
}
|
||||||
|
secs = t - p->ut_time;
|
||||||
|
mins = (secs / 60) % 60;
|
||||||
|
hours = (secs / 3600) % 24;
|
||||||
|
days = secs / 86400;
|
||||||
|
if (days)
|
||||||
|
sprintf(length, "(%d+%02d:%02d)", days, hours, mins);
|
||||||
|
else
|
||||||
|
sprintf(length, " (%02d:%02d)", hours, mins);
|
||||||
|
|
||||||
|
switch(what) {
|
||||||
|
case R_CRASH:
|
||||||
|
sprintf(logouttime, "- crash");
|
||||||
|
break;
|
||||||
|
case R_DOWN:
|
||||||
|
sprintf(logouttime, "- down ");
|
||||||
|
break;
|
||||||
|
case R_NOW:
|
||||||
|
length[0] = 0;
|
||||||
|
if (fulltime)
|
||||||
|
sprintf(logouttime, " still logged in");
|
||||||
|
else {
|
||||||
|
sprintf(logouttime, " still");
|
||||||
|
sprintf(length, "logged in");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R_PHANTOM:
|
||||||
|
length[0] = 0;
|
||||||
|
if (fulltime)
|
||||||
|
sprintf(logouttime, " gone - no logout");
|
||||||
|
else {
|
||||||
|
sprintf(logouttime, " gone");
|
||||||
|
sprintf(length, "- no logout");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R_REBOOT:
|
||||||
|
break;
|
||||||
|
case R_TIMECHANGE:
|
||||||
|
logouttime[0] = 0;
|
||||||
|
length[0] = 0;
|
||||||
|
break;
|
||||||
|
case R_NORMAL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up host with DNS if needed.
|
||||||
|
*/
|
||||||
|
r = -1;
|
||||||
|
if (usedns || useip)
|
||||||
|
r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);
|
||||||
|
if (r < 0) {
|
||||||
|
len = UT_HOSTSIZE;
|
||||||
|
if (len >= sizeof(domain)) len = sizeof(domain) - 1;
|
||||||
|
domain[0] = 0;
|
||||||
|
strncat(domain, p->ut_host, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showhost) {
|
||||||
|
#if CHOP_DOMAIN
|
||||||
|
/*
|
||||||
|
* See if this is in our domain.
|
||||||
|
*/
|
||||||
|
if (!usedns && (s = strchr(p->ut_host, '.')) != NULL &&
|
||||||
|
strcmp(s + 1, domainname) == 0) *s = 0;
|
||||||
|
#endif
|
||||||
|
if (!altlist) {
|
||||||
|
snprintf(final, sizeof(final),
|
||||||
|
fulltime ?
|
||||||
|
"%-8.8s %-12.12s %-16.16s %-24.24s %-26.26s %-12.12s\n" :
|
||||||
|
"%-8.8s %-12.12s %-16.16s %-16.16s %-7.7s %-12.12s\n",
|
||||||
|
p->ut_name, utline,
|
||||||
|
domain, logintime, logouttime, length);
|
||||||
|
} else {
|
||||||
|
snprintf(final, sizeof(final),
|
||||||
|
fulltime ?
|
||||||
|
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
|
||||||
|
"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s %s\n",
|
||||||
|
p->ut_name, utline,
|
||||||
|
logintime, logouttime, length, domain);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
snprintf(final, sizeof(final),
|
||||||
|
fulltime ?
|
||||||
|
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
|
||||||
|
"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
|
||||||
|
p->ut_name, utline,
|
||||||
|
logintime, logouttime, length);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print out "final" string safely.
|
||||||
|
*/
|
||||||
|
for (s = final; *s; s++) {
|
||||||
|
if (*s == '\n' || (*s >= 32 && (unsigned char)*s <= 126))
|
||||||
|
putchar(*s);
|
||||||
|
else
|
||||||
|
putchar('*');
|
||||||
|
}
|
||||||
|
|
||||||
|
recsdone++;
|
||||||
|
if (maxrecs && recsdone >= maxrecs)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* show usage
|
||||||
|
*/
|
||||||
|
void usage(char *s)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s [-num | -n num] [-f file] "
|
||||||
|
"[-t YYYYMMDDHHMMSS] "
|
||||||
|
"[-R] [-adioxF] [username..] [tty..]\n", s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t parsetm(char *ts)
|
||||||
|
{
|
||||||
|
struct tm u, origu;
|
||||||
|
time_t tm;
|
||||||
|
|
||||||
|
memset(&tm, 0, sizeof(tm));
|
||||||
|
|
||||||
|
if (sscanf(ts, "%4d%2d%2d%2d%2d%2d", &u.tm_year,
|
||||||
|
&u.tm_mon, &u.tm_mday, &u.tm_hour, &u.tm_min,
|
||||||
|
&u.tm_sec) != 6)
|
||||||
|
return (time_t)-1;
|
||||||
|
|
||||||
|
u.tm_year -= 1900;
|
||||||
|
u.tm_mon -= 1;
|
||||||
|
u.tm_isdst = -1;
|
||||||
|
|
||||||
|
origu = u;
|
||||||
|
|
||||||
|
if ((tm = mktime(&u)) == (time_t)-1)
|
||||||
|
return tm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfortunately mktime() is much more forgiving than
|
||||||
|
* it should be. For example, it'll gladly accept
|
||||||
|
* "30" as a valid month number. This behavior is by
|
||||||
|
* design, but we don't like it, so we want to detect
|
||||||
|
* it and complain.
|
||||||
|
*/
|
||||||
|
if (u.tm_year != origu.tm_year ||
|
||||||
|
u.tm_mon != origu.tm_mon ||
|
||||||
|
u.tm_mday != origu.tm_mday ||
|
||||||
|
u.tm_hour != origu.tm_hour ||
|
||||||
|
u.tm_min != origu.tm_min ||
|
||||||
|
u.tm_sec != origu.tm_sec)
|
||||||
|
return (time_t)-1;
|
||||||
|
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *fp; /* Filepointer of wtmp file */
|
||||||
|
|
||||||
|
struct utmp ut; /* Current utmp entry */
|
||||||
|
struct utmp oldut; /* Old utmp entry to check for duplicates */
|
||||||
|
struct utmplist *p; /* Pointer into utmplist */
|
||||||
|
struct utmplist *next;/* Pointer into utmplist */
|
||||||
|
|
||||||
|
time_t lastboot = 0; /* Last boottime */
|
||||||
|
time_t lastrch = 0; /* Last run level change */
|
||||||
|
time_t lastdown; /* Last downtime */
|
||||||
|
time_t begintime; /* When wtmp begins */
|
||||||
|
int whydown = 0; /* Why we went down: crash or shutdown */
|
||||||
|
|
||||||
|
int c, x; /* Scratch */
|
||||||
|
struct stat st; /* To stat the [uw]tmp file */
|
||||||
|
int quit = 0; /* Flag */
|
||||||
|
int down = 0; /* Down flag */
|
||||||
|
int lastb = 0; /* Is this 'lastb' ? */
|
||||||
|
int extended = 0; /* Lots of info. */
|
||||||
|
char *altufile = NULL;/* Alternate wtmp */
|
||||||
|
|
||||||
|
time_t until = 0; /* at what time to stop parsing the file */
|
||||||
|
|
||||||
|
progname = mybasename(argv[0]);
|
||||||
|
|
||||||
|
/* Process the arguments. */
|
||||||
|
while((c = getopt(argc, argv, "f:n:RxadFiot:0123456789")) != EOF)
|
||||||
|
switch(c) {
|
||||||
|
case 'R':
|
||||||
|
showhost = 0;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
extended = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
maxrecs = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
oldfmt = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if((altufile = malloc(strlen(optarg)+1)) == NULL) {
|
||||||
|
fprintf(stderr, "%s: out of memory\n",
|
||||||
|
progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
strcpy(altufile, optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
usedns++;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
useip++;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
altlist++;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
fulltime++;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if ((until = parsetm(optarg)) == (time_t)-1) {
|
||||||
|
fprintf(stderr, "%s: Invalid time value \"%s\"\n",
|
||||||
|
progname, optarg);
|
||||||
|
usage(progname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
maxrecs = 10*maxrecs + c - '0';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(progname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (optind < argc) show = argv + optind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Which file do we want to read?
|
||||||
|
*/
|
||||||
|
if (strcmp(progname, "lastb") == 0) {
|
||||||
|
ufile = BTMP_FILE;
|
||||||
|
lastb = 1;
|
||||||
|
} else
|
||||||
|
ufile = WTMP_FILE;
|
||||||
|
if (altufile)
|
||||||
|
ufile = altufile;
|
||||||
|
time(&lastdown);
|
||||||
|
lastrch = lastdown;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill in 'lastdate'
|
||||||
|
*/
|
||||||
|
lastdate = lastdown;
|
||||||
|
|
||||||
|
#if CHOP_DOMAIN
|
||||||
|
/*
|
||||||
|
* Find out domainname.
|
||||||
|
*
|
||||||
|
* This doesn't work on modern systems, where only a DNS
|
||||||
|
* lookup of the result from hostname() will get you the domainname.
|
||||||
|
* Remember that domainname() is the NIS domainname, not DNS.
|
||||||
|
* So basically this whole piece of code is bullshit.
|
||||||
|
*/
|
||||||
|
hostname[0] = 0;
|
||||||
|
(void) gethostname(hostname, sizeof(hostname));
|
||||||
|
if ((domainname = strchr(hostname, '.')) != NULL) domainname++;
|
||||||
|
if (domainname == NULL || domainname[0] == 0) {
|
||||||
|
hostname[0] = 0;
|
||||||
|
(void) getdomainname(hostname, sizeof(hostname));
|
||||||
|
hostname[sizeof(hostname) - 1] = 0;
|
||||||
|
domainname = hostname;
|
||||||
|
if (strcmp(domainname, "(none)") == 0 || domainname[0] == 0)
|
||||||
|
domainname = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install signal handlers
|
||||||
|
*/
|
||||||
|
signal(SIGINT, int_handler);
|
||||||
|
signal(SIGQUIT, quit_handler);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the utmp file
|
||||||
|
*/
|
||||||
|
if ((fp = fopen(ufile, "r")) == NULL) {
|
||||||
|
x = errno;
|
||||||
|
fprintf(stderr, "%s: %s: %s\n", progname, ufile, strerror(errno));
|
||||||
|
if (altufile == NULL && x == ENOENT)
|
||||||
|
fprintf(stderr, "Perhaps this file was removed by the "
|
||||||
|
"operator to prevent logging %s info.\n", progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optimize the buffer size.
|
||||||
|
*/
|
||||||
|
setvbuf(fp, NULL, _IOFBF, UCHUNKSIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read first structure to capture the time field
|
||||||
|
*/
|
||||||
|
if (uread(fp, &ut, NULL) == 1)
|
||||||
|
begintime = ut.ut_time;
|
||||||
|
else {
|
||||||
|
fstat(fileno(fp), &st);
|
||||||
|
begintime = st.st_ctime;
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go to end of file minus one structure
|
||||||
|
* and/or initialize utmp reading code.
|
||||||
|
*/
|
||||||
|
uread(fp, NULL, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read struct after struct backwards from the file.
|
||||||
|
*/
|
||||||
|
while(!quit) {
|
||||||
|
|
||||||
|
if (uread(fp, &ut, &quit) != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (until && until < ut.ut_time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (memcmp(&ut, &oldut, sizeof(struct utmp)) == 0) continue;
|
||||||
|
memcpy(&oldut, &ut, sizeof(struct utmp));
|
||||||
|
lastdate = ut.ut_time;
|
||||||
|
|
||||||
|
if (lastb) {
|
||||||
|
quit = list(&ut, ut.ut_time, R_NORMAL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set ut_type to the correct type.
|
||||||
|
*/
|
||||||
|
if (strncmp(ut.ut_line, "~", 1) == 0) {
|
||||||
|
if (strncmp(ut.ut_user, "shutdown", 8) == 0)
|
||||||
|
ut.ut_type = SHUTDOWN_TIME;
|
||||||
|
else if (strncmp(ut.ut_user, "reboot", 6) == 0)
|
||||||
|
ut.ut_type = BOOT_TIME;
|
||||||
|
else if (strncmp(ut.ut_user, "runlevel", 8) == 0)
|
||||||
|
ut.ut_type = RUN_LVL;
|
||||||
|
}
|
||||||
|
#if 1 /*def COMPAT*/
|
||||||
|
/*
|
||||||
|
* For stupid old applications that don't fill in
|
||||||
|
* ut_type correctly.
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
if (ut.ut_type != DEAD_PROCESS &&
|
||||||
|
ut.ut_name[0] && ut.ut_line[0] &&
|
||||||
|
strcmp(ut.ut_name, "LOGIN") != 0)
|
||||||
|
ut.ut_type = USER_PROCESS;
|
||||||
|
/*
|
||||||
|
* Even worse, applications that write ghost
|
||||||
|
* entries: ut_type set to USER_PROCESS but
|
||||||
|
* empty ut_name...
|
||||||
|
*/
|
||||||
|
if (ut.ut_name[0] == 0)
|
||||||
|
ut.ut_type = DEAD_PROCESS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clock changes.
|
||||||
|
*/
|
||||||
|
if (strcmp(ut.ut_name, "date") == 0) {
|
||||||
|
if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
|
||||||
|
if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (ut.ut_type) {
|
||||||
|
case SHUTDOWN_TIME:
|
||||||
|
if (extended) {
|
||||||
|
strcpy(ut.ut_line, "system down");
|
||||||
|
quit = list(&ut, lastboot, R_NORMAL);
|
||||||
|
}
|
||||||
|
lastdown = lastrch = ut.ut_time;
|
||||||
|
down = 1;
|
||||||
|
break;
|
||||||
|
case OLD_TIME:
|
||||||
|
case NEW_TIME:
|
||||||
|
if (extended) {
|
||||||
|
strcpy(ut.ut_line,
|
||||||
|
ut.ut_type == NEW_TIME ? "new time" :
|
||||||
|
"old time");
|
||||||
|
quit = list(&ut, lastdown, R_TIMECHANGE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BOOT_TIME:
|
||||||
|
strcpy(ut.ut_line, "system boot");
|
||||||
|
quit = list(&ut, lastdown, R_REBOOT);
|
||||||
|
lastboot = ut.ut_time;
|
||||||
|
down = 1;
|
||||||
|
break;
|
||||||
|
case RUN_LVL:
|
||||||
|
x = ut.ut_pid & 255;
|
||||||
|
if (extended) {
|
||||||
|
sprintf(ut.ut_line, "(to lvl %c)", x);
|
||||||
|
quit = list(&ut, lastrch, R_NORMAL);
|
||||||
|
}
|
||||||
|
if (x == '0' || x == '6') {
|
||||||
|
lastdown = ut.ut_time;
|
||||||
|
down = 1;
|
||||||
|
ut.ut_type = SHUTDOWN_TIME;
|
||||||
|
}
|
||||||
|
lastrch = ut.ut_time;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USER_PROCESS:
|
||||||
|
/*
|
||||||
|
* This was a login - show the first matching
|
||||||
|
* logout record and delete all records with
|
||||||
|
* the same ut_line.
|
||||||
|
*/
|
||||||
|
c = 0;
|
||||||
|
for (p = utmplist; p; p = next) {
|
||||||
|
next = p->next;
|
||||||
|
if (strncmp(p->ut.ut_line, ut.ut_line,
|
||||||
|
UT_LINESIZE) == 0) {
|
||||||
|
/* Show it */
|
||||||
|
if (c == 0) {
|
||||||
|
quit = list(&ut, p->ut.ut_time,
|
||||||
|
R_NORMAL);
|
||||||
|
c = 1;
|
||||||
|
}
|
||||||
|
if (p->next) p->next->prev = p->prev;
|
||||||
|
if (p->prev)
|
||||||
|
p->prev->next = p->next;
|
||||||
|
else
|
||||||
|
utmplist = p->next;
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Not found? Then crashed, down, still
|
||||||
|
* logged in, or missing logout record.
|
||||||
|
*/
|
||||||
|
if (c == 0) {
|
||||||
|
if (lastboot == 0) {
|
||||||
|
c = R_NOW;
|
||||||
|
/* Is process still alive? */
|
||||||
|
if (ut.ut_pid > 0 &&
|
||||||
|
kill(ut.ut_pid, 0) != 0 &&
|
||||||
|
errno == ESRCH)
|
||||||
|
c = R_PHANTOM;
|
||||||
|
} else
|
||||||
|
c = whydown;
|
||||||
|
quit = list(&ut, lastboot, c);
|
||||||
|
}
|
||||||
|
/* FALLTHRU */
|
||||||
|
|
||||||
|
case DEAD_PROCESS:
|
||||||
|
/*
|
||||||
|
* Just store the data if it is
|
||||||
|
* interesting enough.
|
||||||
|
*/
|
||||||
|
if (ut.ut_line[0] == 0)
|
||||||
|
break;
|
||||||
|
if ((p = malloc(sizeof(struct utmplist))) == NULL) {
|
||||||
|
fprintf(stderr, "%s: out of memory\n",
|
||||||
|
progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memcpy(&p->ut, &ut, sizeof(struct utmp));
|
||||||
|
p->next = utmplist;
|
||||||
|
p->prev = NULL;
|
||||||
|
if (utmplist) utmplist->prev = p;
|
||||||
|
utmplist = p;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If we saw a shutdown/reboot record we can remove
|
||||||
|
* the entire current utmplist.
|
||||||
|
*/
|
||||||
|
if (down) {
|
||||||
|
lastboot = ut.ut_time;
|
||||||
|
whydown = (ut.ut_type == SHUTDOWN_TIME) ? R_DOWN : R_CRASH;
|
||||||
|
for (p = utmplist; p; p = next) {
|
||||||
|
next = p->next;
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
utmplist = NULL;
|
||||||
|
down = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n%s begins %s", mybasename(ufile), ctime(&begintime));
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should we free memory here? Nah. This is not NT :)
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
124
src/mesg.c
Normal file
124
src/mesg.c
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* mesg.c The "mesg" utility. Gives / restrict access to
|
||||||
|
* your terminal by others.
|
||||||
|
*
|
||||||
|
* Usage: mesg [y|n].
|
||||||
|
* Without arguments prints out the current settings.
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2001 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
char *Version = "@(#) mesg 2.81 31-Jul-2001 miquels@cistron.nl";
|
||||||
|
|
||||||
|
#define TTYGRP "tty"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if the system has a special 'tty' group.
|
||||||
|
* If it does, and the tty device is in that group,
|
||||||
|
* we set the modes to -rw--w--- instead if -rw--w--w.
|
||||||
|
*/
|
||||||
|
int hasttygrp(void)
|
||||||
|
{
|
||||||
|
struct group *grp;
|
||||||
|
|
||||||
|
if ((grp = getgrnam(TTYGRP)) != NULL)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if the tty devices group is indeed 'tty'
|
||||||
|
*/
|
||||||
|
int tty_in_ttygrp(struct stat *st)
|
||||||
|
{
|
||||||
|
struct group *gr;
|
||||||
|
|
||||||
|
if ((gr = getgrgid(st->st_gid)) == NULL)
|
||||||
|
return 0;
|
||||||
|
if (strcmp(gr->gr_name, TTYGRP) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
unsigned int ttymode, st_mode_old;
|
||||||
|
int ht;
|
||||||
|
int it;
|
||||||
|
int e;
|
||||||
|
|
||||||
|
if (!isatty(0)) {
|
||||||
|
/* Or should we look in /var/run/utmp? */
|
||||||
|
fprintf(stderr, "stdin: is not a tty\n");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(0, &st) < 0) {
|
||||||
|
perror("fstat");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ht = hasttygrp();
|
||||||
|
it = tty_in_ttygrp(&st);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
ttymode = (ht && it) ? 020 : 002;
|
||||||
|
printf("is %s\n", (st.st_mode & ttymode) ? "y" : "n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (argc > 2 || (argv[1][0] != 'y' && argv[1][0] != 'n')) {
|
||||||
|
fprintf(stderr, "Usage: mesg [y|n]\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Security check: allow mesg n when group is
|
||||||
|
* weird, but don't allow mesg y.
|
||||||
|
*/
|
||||||
|
ttymode = ht ? 020 : 022;
|
||||||
|
if (ht && !it && argv[1][0] == 'y') {
|
||||||
|
fprintf(stderr, "mesg: error: tty device is not owned "
|
||||||
|
"by group `%s'\n", TTYGRP);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
st_mode_old = st.st_mode;
|
||||||
|
if (argv[1][0] == 'y')
|
||||||
|
st.st_mode |= ttymode;
|
||||||
|
else
|
||||||
|
st.st_mode &= ~(ttymode);
|
||||||
|
if (st_mode_old != st.st_mode && fchmod(0, st.st_mode) != 0) {
|
||||||
|
e = errno;
|
||||||
|
fprintf(stderr, "mesg: %s: %s\n",
|
||||||
|
ttyname(0), strerror(e));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
128
src/mountpoint.c
Normal file
128
src/mountpoint.c
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* mountpoint See if a directory is a mountpoint.
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* Version: @(#)mountpoint 2.85-12 17-Mar-2004 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int dostat(char *path, struct stat *st, int do_lstat, int quiet)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (do_lstat)
|
||||||
|
n = lstat(path, st);
|
||||||
|
else
|
||||||
|
n = stat(path, st);
|
||||||
|
|
||||||
|
if (n != 0) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, "mountpoint: %s: %s\n", path,
|
||||||
|
strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(void) {
|
||||||
|
fprintf(stderr, "Usage: mountpoint [-q] [-d] [-x] path\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct stat st, st2;
|
||||||
|
char buf[256];
|
||||||
|
char *path;
|
||||||
|
int quiet = 0;
|
||||||
|
int showdev = 0;
|
||||||
|
int xdev = 0;
|
||||||
|
int c, r;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "dqx")) != EOF) switch(c) {
|
||||||
|
case 'd':
|
||||||
|
showdev = 1;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
quiet = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
xdev = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (optind != argc - 1) usage();
|
||||||
|
path = argv[optind];
|
||||||
|
|
||||||
|
if (dostat(path, &st, !xdev, quiet) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (xdev) {
|
||||||
|
#ifdef __linux__
|
||||||
|
if (!S_ISBLK(st.st_mode))
|
||||||
|
#else
|
||||||
|
if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (quiet)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "mountpoint: %s: not a block device\n",
|
||||||
|
path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("%u:%u\n", major(st.st_rdev), minor(st.st_rdev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, "mountpoint: %s: not a directory\n",
|
||||||
|
path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
strncpy(buf, path, sizeof(buf) - 4);
|
||||||
|
strcat(buf, "/..");
|
||||||
|
if (dostat(buf, &st2, 0, quiet) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
r = (st.st_dev != st2.st_dev) ||
|
||||||
|
(st.st_dev == st2.st_dev && st.st_ino == st2.st_ino);
|
||||||
|
|
||||||
|
if (!quiet && !showdev)
|
||||||
|
printf("%s is %sa mountpoint\n", path, r ? "" : "not ");
|
||||||
|
if (showdev)
|
||||||
|
printf("%u:%u\n", major(st.st_dev), minor(st.st_dev));
|
||||||
|
|
||||||
|
return r ? 0 : 1;
|
||||||
|
}
|
41
src/oldutmp.h
Normal file
41
src/oldutmp.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* oldutmp.h Definition of the old libc5 utmp structure.
|
||||||
|
*
|
||||||
|
* Version: @(#)oldutmp.h 1.00 29-Mar-1998 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991-2000 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef OLD_UTMP_H
|
||||||
|
#define OLD_UTMP_H
|
||||||
|
|
||||||
|
#define OLD_LINESIZE 12
|
||||||
|
#define OLD_NAMESIZE 8
|
||||||
|
#define OLD_HOSTSIZE 16
|
||||||
|
|
||||||
|
struct oldutmp {
|
||||||
|
short ut_type;
|
||||||
|
int ut_pid;
|
||||||
|
char ut_line[OLD_LINESIZE];
|
||||||
|
char ut_id[4];
|
||||||
|
long ut_oldtime;
|
||||||
|
char ut_user[OLD_NAMESIZE];
|
||||||
|
char ut_host[OLD_HOSTSIZE];
|
||||||
|
long ut_oldaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
49
src/paths.h
Normal file
49
src/paths.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* paths.h Paths of files that init and related utilities need.
|
||||||
|
*
|
||||||
|
* Version: @(#) paths.h 2.85-8 05-Nov-2003
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, <miquels@cistron.nl>
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2001 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#define VT_MASTER "/dev/tty0" /* Virtual console master */
|
||||||
|
#define CONSOLE "/dev/console" /* Logical system console */
|
||||||
|
#define SECURETTY "/etc/securetty" /* List of root terminals */
|
||||||
|
#define SDALLOW "/etc/shutdown.allow" /* Users allowed to shutdown */
|
||||||
|
#define INITTAB "/etc/inittab" /* Location of inittab */
|
||||||
|
#define INIT "/sbin/init" /* Location of init itself. */
|
||||||
|
#define NOLOGIN "/etc/nologin" /* Stop user logging in. */
|
||||||
|
#define FASTBOOT "/fastboot" /* Enable fast boot. */
|
||||||
|
#define FORCEFSCK "/forcefsck" /* Force fsck on boot */
|
||||||
|
#define SDPID "/var/run/shutdown.pid" /* PID of shutdown program */
|
||||||
|
#define SHELL "/bin/sh" /* Default shell */
|
||||||
|
#define SULOGIN "/sbin/sulogin" /* Sulogin */
|
||||||
|
#define INITSCRIPT "/etc/initscript" /* Initscript. */
|
||||||
|
#define PWRSTAT "/etc/powerstatus" /* COMPAT: SIGPWR reason (OK/BAD) */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define INITLVL "/etc/initrunlvl" /* COMPAT: New runlevel */
|
||||||
|
#define INITLVL2 "/var/log/initrunlvl" /* COMPAT: New runlevel */
|
||||||
|
/* Note: INITLVL2 definition needs INITLVL */
|
||||||
|
#define HALTSCRIPT1 "/etc/init.d/halt" /* Called by "fast" shutdown */
|
||||||
|
#define HALTSCRIPT2 "/etc/rc.d/rc.0" /* Called by "fast" shutdown */
|
||||||
|
#define REBOOTSCRIPT1 "/etc/init.d/reboot" /* Ditto. */
|
||||||
|
#define REBOOTSCRIPT2 "/etc/rc.d/rc.6" /* Ditto. */
|
||||||
|
#endif
|
||||||
|
|
51
src/reboot.h
Normal file
51
src/reboot.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* reboot.h Headerfile that defines how to handle
|
||||||
|
* the reboot() system call.
|
||||||
|
*
|
||||||
|
* Version: @(#)reboot.h 2.85-17 04-Jun-2004 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Copyright (C) (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
#ifdef RB_ENABLE_CAD
|
||||||
|
# define BMAGIC_HARD RB_ENABLE_CAD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RB_DISABLE_CAD
|
||||||
|
# define BMAGIC_SOFT RB_DISABLE_CAD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RB_HALT_SYSTEM
|
||||||
|
# define BMAGIC_HALT RB_HALT_SYSTEM
|
||||||
|
#else
|
||||||
|
# define BMAGIC_HALT RB_HALT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BMAGIC_REBOOT RB_AUTOBOOT
|
||||||
|
|
||||||
|
#ifdef RB_POWER_OFF
|
||||||
|
# define BMAGIC_POWEROFF RB_POWER_OFF
|
||||||
|
#elif defined(RB_POWEROFF)
|
||||||
|
# define BMAGIC_POWEROFF RB_POWEROFF
|
||||||
|
#else
|
||||||
|
# define BMAGIC_POWEROFF BMAGIC_HALT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define init_reboot(magic) reboot(magic)
|
||||||
|
|
53
src/runlevel.c
Normal file
53
src/runlevel.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* runlevel Prints out the previous and the current runlevel.
|
||||||
|
*
|
||||||
|
* Version: @(#)runlevel 1.20 16-Apr-1997 MvS
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-1997 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
struct utmp *ut;
|
||||||
|
char prev;
|
||||||
|
|
||||||
|
if (argc > 1) utmpname(argv[1]);
|
||||||
|
|
||||||
|
setutent();
|
||||||
|
while ((ut = getutent()) != NULL) {
|
||||||
|
if (ut->ut_type == RUN_LVL) {
|
||||||
|
prev = ut->ut_pid / 256;
|
||||||
|
if (prev == 0) prev = 'N';
|
||||||
|
printf("%c %c\n", prev, ut->ut_pid % 256);
|
||||||
|
endutent();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("unknown\n");
|
||||||
|
endutent();
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
28
src/set.h
Normal file
28
src/set.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* set.h Macros that look like sigaddset et al. but
|
||||||
|
* aren't. They are used to manipulate bits in
|
||||||
|
* an integer, to do our signal bookeeping.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ISMEMBER(set, val) ((set) & (1 << (val)))
|
||||||
|
#define DELSET(set, val) ((set) &= ~(1 << (val)))
|
||||||
|
#define ADDSET(set, val) ((set) |= (1 << (val)))
|
||||||
|
#define EMPTYSET(set) ((set) = 0)
|
||||||
|
|
727
src/shutdown.c
Normal file
727
src/shutdown.c
Normal file
@ -0,0 +1,727 @@
|
|||||||
|
/*
|
||||||
|
* shutdown.c Shut the system down.
|
||||||
|
*
|
||||||
|
* Usage: shutdown [-krhfnc] time [warning message]
|
||||||
|
* -k: don't really shutdown, only warn.
|
||||||
|
* -r: reboot after shutdown.
|
||||||
|
* -h: halt after shutdown.
|
||||||
|
* -f: do a 'fast' reboot (skip fsck).
|
||||||
|
* -F: Force fsck on reboot.
|
||||||
|
* -n: do not go through init but do it ourselves.
|
||||||
|
* -c: cancel an already running shutdown.
|
||||||
|
* -t secs: delay between SIGTERM and SIGKILL for init.
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Version: @(#)shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include "paths.h"
|
||||||
|
#include "reboot.h"
|
||||||
|
#include "initreq.h"
|
||||||
|
|
||||||
|
char *Version = "@(#) shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl";
|
||||||
|
|
||||||
|
#define MESSAGELEN 256
|
||||||
|
|
||||||
|
int dontshut = 0; /* Don't shutdown, only warn */
|
||||||
|
char down_level[2]; /* What runlevel to go to. */
|
||||||
|
int dosync = 1; /* Sync before reboot or halt */
|
||||||
|
int fastboot = 0; /* Do a 'fast' reboot */
|
||||||
|
int forcefsck = 0; /* Force fsck on reboot */
|
||||||
|
char message[MESSAGELEN]; /* Warning message */
|
||||||
|
char *sltime = 0; /* Sleep time */
|
||||||
|
char newstate[64]; /* What are we gonna do */
|
||||||
|
int doself = 0; /* Don't use init */
|
||||||
|
int got_alrm = 0;
|
||||||
|
|
||||||
|
char *clean_env[] = {
|
||||||
|
"HOME=/",
|
||||||
|
"PATH=/bin:/usr/bin:/sbin:/usr/sbin",
|
||||||
|
"TERM=dumb",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* From "wall.c" */
|
||||||
|
extern void wall(char *, int, int);
|
||||||
|
|
||||||
|
/* From "utmp.c" */
|
||||||
|
extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sleep without being interrupted.
|
||||||
|
*/
|
||||||
|
void hardsleep(int secs)
|
||||||
|
{
|
||||||
|
struct timespec ts, rem;
|
||||||
|
|
||||||
|
ts.tv_sec = secs;
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
|
||||||
|
while(nanosleep(&ts, &rem) < 0 && errno == EINTR)
|
||||||
|
ts = rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Break off an already running shutdown.
|
||||||
|
*/
|
||||||
|
void stopit(int sig)
|
||||||
|
{
|
||||||
|
unlink(NOLOGIN);
|
||||||
|
unlink(FASTBOOT);
|
||||||
|
unlink(FORCEFSCK);
|
||||||
|
unlink(SDPID);
|
||||||
|
printf("\r\nShutdown cancelled.\r\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show usage message.
|
||||||
|
*/
|
||||||
|
void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Usage:\t shutdown [-akrhHPfnc] [-t secs] time [warning message]\n"
|
||||||
|
"\t\t -a: use /etc/shutdown.allow\n"
|
||||||
|
"\t\t -k: don't really shutdown, only warn.\n"
|
||||||
|
"\t\t -r: reboot after shutdown.\n"
|
||||||
|
"\t\t -h: halt after shutdown.\n"
|
||||||
|
"\t\t -P: halt action is to turn off power.\n"
|
||||||
|
"\t\t -H: halt action is to just halt.\n"
|
||||||
|
"\t\t -f: do a 'fast' reboot (skip fsck).\n"
|
||||||
|
"\t\t -F: Force fsck on reboot.\n"
|
||||||
|
"\t\t -n: do not go through \"init\" but go down real fast.\n"
|
||||||
|
"\t\t -c: cancel a running shutdown.\n"
|
||||||
|
"\t\t -t secs: delay between warning and kill signal.\n"
|
||||||
|
"\t\t ** the \"time\" argument is mandatory! (try \"now\") **\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void alrm_handler(int sig)
|
||||||
|
{
|
||||||
|
got_alrm = sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set environment variables in the init process.
|
||||||
|
*/
|
||||||
|
int init_setenv(char *name, char *value)
|
||||||
|
{
|
||||||
|
struct init_request request;
|
||||||
|
struct sigaction sa;
|
||||||
|
int fd;
|
||||||
|
int nl, vl;
|
||||||
|
|
||||||
|
memset(&request, 0, sizeof(request));
|
||||||
|
request.magic = INIT_MAGIC;
|
||||||
|
request.cmd = INIT_CMD_SETENV;
|
||||||
|
nl = strlen(name);
|
||||||
|
vl = value ? strlen(value) : 0;
|
||||||
|
|
||||||
|
if (nl + vl + 3 >= sizeof(request.i.data))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy(request.i.data, name, nl);
|
||||||
|
if (value) {
|
||||||
|
request.i.data[nl] = '=';
|
||||||
|
memcpy(request.i.data + nl + 1, value, vl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the fifo and write the command.
|
||||||
|
* Make sure we don't hang on opening /dev/initctl
|
||||||
|
*/
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = alrm_handler;
|
||||||
|
sigaction(SIGALRM, &sa, NULL);
|
||||||
|
got_alrm = 0;
|
||||||
|
alarm(3);
|
||||||
|
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0 &&
|
||||||
|
write(fd, &request, sizeof(request)) == sizeof(request)) {
|
||||||
|
close(fd);
|
||||||
|
alarm(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "shutdown: ");
|
||||||
|
if (got_alrm) {
|
||||||
|
fprintf(stderr, "timeout opening/writing control channel %s\n",
|
||||||
|
INIT_FIFO);
|
||||||
|
} else {
|
||||||
|
perror(INIT_FIFO);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell everyone the system is going down in 'mins' minutes.
|
||||||
|
*/
|
||||||
|
void warn(int mins)
|
||||||
|
{
|
||||||
|
char buf[MESSAGELEN + sizeof(newstate)];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
buf[0] = 0;
|
||||||
|
strncat(buf, message, sizeof(buf) - 1);
|
||||||
|
len = strlen(buf);
|
||||||
|
|
||||||
|
if (mins == 0)
|
||||||
|
snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
"\rThe system is going down %s NOW!\r\n",
|
||||||
|
newstate);
|
||||||
|
else
|
||||||
|
snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
"\rThe system is going DOWN %s in %d minute%s!\r\n",
|
||||||
|
newstate, mins, mins == 1 ? "" : "s");
|
||||||
|
wall(buf, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the /etc/nologin file.
|
||||||
|
*/
|
||||||
|
void donologin(int min)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
time(&t);
|
||||||
|
t += 60 * min;
|
||||||
|
|
||||||
|
if ((fp = fopen(NOLOGIN, "w")) != NULL) {
|
||||||
|
fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
|
||||||
|
if (message[0]) fputs(message, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spawn an external program.
|
||||||
|
*/
|
||||||
|
int spawn(int noerr, char *prog, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
pid_t pid, rc;
|
||||||
|
int i;
|
||||||
|
char *argv[8];
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while ((pid = fork()) < 0 && i < 10) {
|
||||||
|
perror("fork");
|
||||||
|
sleep(5);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid < 0) return -1;
|
||||||
|
|
||||||
|
if (pid > 0) {
|
||||||
|
while((rc = wait(&i)) != pid)
|
||||||
|
if (rc < 0 && errno == ECHILD)
|
||||||
|
break;
|
||||||
|
return (rc == pid) ? WEXITSTATUS(i) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noerr) fclose(stderr);
|
||||||
|
|
||||||
|
argv[0] = prog;
|
||||||
|
va_start(ap, prog);
|
||||||
|
for (i = 1; i < 7 && (argv[i] = va_arg(ap, char *)) != NULL; i++)
|
||||||
|
;
|
||||||
|
argv[i] = NULL;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
chdir("/");
|
||||||
|
environ = clean_env;
|
||||||
|
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
perror(argv[0]);
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
/*NOTREACHED*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kill all processes, call /etc/init.d/halt (if present)
|
||||||
|
*/
|
||||||
|
void fastdown()
|
||||||
|
{
|
||||||
|
int do_halt = (down_level[0] == '0');
|
||||||
|
int i;
|
||||||
|
#if 0
|
||||||
|
char cmd[128];
|
||||||
|
char *script;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently, the halt script is either init.d/halt OR rc.d/rc.0,
|
||||||
|
* likewise for the reboot script. Test for the presence
|
||||||
|
* of either.
|
||||||
|
*/
|
||||||
|
if (do_halt) {
|
||||||
|
if (access(HALTSCRIPT1, X_OK) == 0)
|
||||||
|
script = HALTSCRIPT1;
|
||||||
|
else
|
||||||
|
script = HALTSCRIPT2;
|
||||||
|
} else {
|
||||||
|
if (access(REBOOTSCRIPT1, X_OK) == 0)
|
||||||
|
script = REBOOTSCRIPT1;
|
||||||
|
else
|
||||||
|
script = REBOOTSCRIPT2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* First close all files. */
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
if (!isatty(i)) {
|
||||||
|
close(i);
|
||||||
|
open("/dev/null", O_RDWR);
|
||||||
|
}
|
||||||
|
for(i = 3; i < 20; i++) close(i);
|
||||||
|
close(255);
|
||||||
|
|
||||||
|
/* First idle init. */
|
||||||
|
if (kill(1, SIGTSTP) < 0) {
|
||||||
|
fprintf(stderr, "shutdown: can't idle init.\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kill all processes. */
|
||||||
|
fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
|
||||||
|
kill(-1, SIGTERM);
|
||||||
|
sleep(sltime ? atoi(sltime) : 3);
|
||||||
|
fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
|
||||||
|
(void) kill(-1, SIGKILL);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* See if we can run /etc/init.d/halt */
|
||||||
|
if (access(script, X_OK) == 0) {
|
||||||
|
spawn(1, cmd, "fast", NULL);
|
||||||
|
fprintf(stderr, "shutdown: %s returned - falling back "
|
||||||
|
"on default routines\r\n", script);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* script failed or not present: do it ourself. */
|
||||||
|
sleep(1); /* Give init the chance to collect zombies. */
|
||||||
|
|
||||||
|
/* Record the fact that we're going down */
|
||||||
|
write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
|
||||||
|
|
||||||
|
/* This is for those who have quota installed. */
|
||||||
|
spawn(1, "accton", NULL);
|
||||||
|
spawn(1, "quotaoff", "-a", NULL);
|
||||||
|
|
||||||
|
sync();
|
||||||
|
fprintf(stderr, "shutdown: turning off swap\r\n");
|
||||||
|
spawn(0, "swapoff", "-a", NULL);
|
||||||
|
fprintf(stderr, "shutdown: unmounting all file systems\r\n");
|
||||||
|
spawn(0, "umount", "-a", NULL);
|
||||||
|
|
||||||
|
/* We're done, halt or reboot now. */
|
||||||
|
if (do_halt) {
|
||||||
|
fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL "
|
||||||
|
"or turn off power\r\n");
|
||||||
|
init_reboot(BMAGIC_HALT);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Please stand by while rebooting the system.\r\n");
|
||||||
|
init_reboot(BMAGIC_REBOOT);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go to runlevel 0, 1 or 6.
|
||||||
|
*/
|
||||||
|
void shutdown(char *halttype)
|
||||||
|
{
|
||||||
|
char *args[8];
|
||||||
|
int argp = 0;
|
||||||
|
int do_halt = (down_level[0] == '0');
|
||||||
|
|
||||||
|
/* Warn for the last time */
|
||||||
|
warn(0);
|
||||||
|
if (dontshut) {
|
||||||
|
hardsleep(1);
|
||||||
|
stopit(0);
|
||||||
|
}
|
||||||
|
openlog("shutdown", LOG_PID, LOG_USER);
|
||||||
|
if (do_halt)
|
||||||
|
syslog(LOG_NOTICE, "shutting down for system halt");
|
||||||
|
else
|
||||||
|
syslog(LOG_NOTICE, "shutting down for system reboot");
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
/* See if we have to do it ourself. */
|
||||||
|
if (doself) fastdown();
|
||||||
|
|
||||||
|
/* Create the arguments for init. */
|
||||||
|
args[argp++] = INIT;
|
||||||
|
if (sltime) {
|
||||||
|
args[argp++] = "-t";
|
||||||
|
args[argp++] = sltime;
|
||||||
|
}
|
||||||
|
args[argp++] = down_level;
|
||||||
|
args[argp] = (char *)NULL;
|
||||||
|
|
||||||
|
unlink(SDPID);
|
||||||
|
unlink(NOLOGIN);
|
||||||
|
|
||||||
|
/* Now execute init to change runlevel. */
|
||||||
|
sync();
|
||||||
|
init_setenv("INIT_HALT", halttype);
|
||||||
|
execv(INIT, args);
|
||||||
|
|
||||||
|
/* Oops - failed. */
|
||||||
|
fprintf(stderr, "\rshutdown: cannot execute %s\r\n", INIT);
|
||||||
|
unlink(FASTBOOT);
|
||||||
|
unlink(FORCEFSCK);
|
||||||
|
init_setenv("INIT_HALT", NULL);
|
||||||
|
openlog("shutdown", LOG_PID, LOG_USER);
|
||||||
|
syslog(LOG_NOTICE, "shutdown failed");
|
||||||
|
closelog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns if a warning is to be sent for wt
|
||||||
|
*/
|
||||||
|
static int needwarning(int wt)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (wt < 10)
|
||||||
|
ret = 1;
|
||||||
|
else if (wt < 60)
|
||||||
|
ret = (wt % 15 == 0);
|
||||||
|
else if (wt < 180)
|
||||||
|
ret = (wt % 30 == 0);
|
||||||
|
else
|
||||||
|
ret = (wt % 60 == 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main program.
|
||||||
|
* Process the options and do the final countdown.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
extern int getopt();
|
||||||
|
extern int optind;
|
||||||
|
struct sigaction sa;
|
||||||
|
struct tm *lt;
|
||||||
|
struct stat st;
|
||||||
|
struct utmp *ut;
|
||||||
|
time_t t;
|
||||||
|
uid_t realuid;
|
||||||
|
char *halttype;
|
||||||
|
char *downusers[32];
|
||||||
|
char buf[128];
|
||||||
|
char term[UT_LINESIZE + 6];
|
||||||
|
char *sp;
|
||||||
|
char *when = NULL;
|
||||||
|
int c, i, wt;
|
||||||
|
int hours, mins;
|
||||||
|
int didnolog = 0;
|
||||||
|
int cancel = 0;
|
||||||
|
int useacl = 0;
|
||||||
|
int pid = 0;
|
||||||
|
int user_ok = 0;
|
||||||
|
|
||||||
|
/* We can be installed setuid root (executable for a special group) */
|
||||||
|
realuid = getuid();
|
||||||
|
setuid(geteuid());
|
||||||
|
|
||||||
|
if (getuid() != 0) {
|
||||||
|
fprintf(stderr, "shutdown: you must be root to do that!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
strcpy(down_level, "1");
|
||||||
|
halttype = NULL;
|
||||||
|
|
||||||
|
/* Process the options. */
|
||||||
|
while((c = getopt(argc, argv, "HPacqkrhnfFyt:g:i:")) != EOF) {
|
||||||
|
switch(c) {
|
||||||
|
case 'H':
|
||||||
|
halttype = "HALT";
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
halttype = "POWERDOWN";
|
||||||
|
break;
|
||||||
|
case 'a': /* Access control. */
|
||||||
|
useacl = 1;
|
||||||
|
break;
|
||||||
|
case 'c': /* Cancel an already running shutdown. */
|
||||||
|
cancel = 1;
|
||||||
|
break;
|
||||||
|
case 'k': /* Don't really shutdown, only warn.*/
|
||||||
|
dontshut = 1;
|
||||||
|
break;
|
||||||
|
case 'r': /* Automatic reboot */
|
||||||
|
down_level[0] = '6';
|
||||||
|
break;
|
||||||
|
case 'h': /* Halt after shutdown */
|
||||||
|
down_level[0] = '0';
|
||||||
|
break;
|
||||||
|
case 'f': /* Don't perform fsck after next boot */
|
||||||
|
fastboot = 1;
|
||||||
|
break;
|
||||||
|
case 'F': /* Force fsck after next boot */
|
||||||
|
forcefsck = 1;
|
||||||
|
break;
|
||||||
|
case 'n': /* Don't switch runlevels. */
|
||||||
|
doself = 1;
|
||||||
|
break;
|
||||||
|
case 't': /* Delay between TERM and KILL */
|
||||||
|
sltime = optarg;
|
||||||
|
break;
|
||||||
|
case 'y': /* Ignored for sysV compatibility */
|
||||||
|
break;
|
||||||
|
case 'g': /* sysv style to specify time. */
|
||||||
|
when = optarg;
|
||||||
|
break;
|
||||||
|
case 'i': /* Level to go to. */
|
||||||
|
if (!strchr("0156aAbBcCsS", optarg[0])) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"shutdown: `%s': bad runlevel\n",
|
||||||
|
optarg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
down_level[0] = optarg[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != halttype && down_level[0] != '0') {
|
||||||
|
fprintf(stderr, "shutdown: -H and -P flags can only be used along with -h flag.\n");
|
||||||
|
usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do we need to use the shutdown.allow file ? */
|
||||||
|
if (useacl && (fp = fopen(SDALLOW, "r")) != NULL) {
|
||||||
|
|
||||||
|
/* Read /etc/shutdown.allow. */
|
||||||
|
i = 0;
|
||||||
|
while(fgets(buf, 128, fp)) {
|
||||||
|
if (buf[0] == '#' || buf[0] == '\n') continue;
|
||||||
|
if (i > 31) continue;
|
||||||
|
for(sp = buf; *sp; sp++) if (*sp == '\n') *sp = 0;
|
||||||
|
downusers[i++] = strdup(buf);
|
||||||
|
}
|
||||||
|
if (i < 32) downusers[i] = 0;
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/* Now walk through /var/run/utmp to find logged in users. */
|
||||||
|
while(!user_ok && (ut = getutent()) != NULL) {
|
||||||
|
|
||||||
|
/* See if this is a user process on a VC. */
|
||||||
|
if (ut->ut_type != USER_PROCESS) continue;
|
||||||
|
sprintf(term, "/dev/%.*s", UT_LINESIZE, ut->ut_line);
|
||||||
|
if (stat(term, &st) < 0) continue;
|
||||||
|
#ifdef major /* glibc */
|
||||||
|
if (major(st.st_rdev) != 4 ||
|
||||||
|
minor(st.st_rdev) > 63) continue;
|
||||||
|
#else
|
||||||
|
if ((st.st_rdev & 0xFFC0) != 0x0400) continue;
|
||||||
|
#endif
|
||||||
|
/* Root is always OK. */
|
||||||
|
if (strcmp(ut->ut_user, "root") == 0) {
|
||||||
|
user_ok++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if this is an allowed user. */
|
||||||
|
for(i = 0; i < 32 && downusers[i]; i++)
|
||||||
|
if (!strncmp(downusers[i], ut->ut_user,
|
||||||
|
UT_NAMESIZE)) {
|
||||||
|
user_ok++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endutent();
|
||||||
|
|
||||||
|
/* See if user was allowed. */
|
||||||
|
if (!user_ok) {
|
||||||
|
if ((fp = fopen(CONSOLE, "w")) != NULL) {
|
||||||
|
fprintf(fp, "\rshutdown: no authorized users "
|
||||||
|
"logged in.\r\n");
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read pid of running shutdown from a file */
|
||||||
|
if ((fp = fopen(SDPID, "r")) != NULL) {
|
||||||
|
fscanf(fp, "%d", &pid);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read remaining words, skip time if needed. */
|
||||||
|
message[0] = 0;
|
||||||
|
for(c = optind + (!cancel && !when); c < argc; c++) {
|
||||||
|
if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN)
|
||||||
|
break;
|
||||||
|
strcat(message, argv[c]);
|
||||||
|
strcat(message, " ");
|
||||||
|
}
|
||||||
|
if (message[0]) strcat(message, "\r\n");
|
||||||
|
|
||||||
|
/* See if we want to run or cancel. */
|
||||||
|
if (cancel) {
|
||||||
|
if (pid <= 0) {
|
||||||
|
fprintf(stderr, "shutdown: cannot find pid "
|
||||||
|
"of running shutdown.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
init_setenv("INIT_HALT", NULL);
|
||||||
|
if (kill(pid, SIGINT) < 0) {
|
||||||
|
fprintf(stderr, "shutdown: not running.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (message[0]) wall(message, 1, 0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check syntax. */
|
||||||
|
if (when == NULL) {
|
||||||
|
if (optind == argc) usage();
|
||||||
|
when = argv[optind++];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we are already running. */
|
||||||
|
if (pid > 0 && kill(pid, 0) == 0) {
|
||||||
|
fprintf(stderr, "\rshutdown: already running.\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra check. */
|
||||||
|
if (doself && down_level[0] != '0' && down_level[0] != '6') {
|
||||||
|
fprintf(stderr,
|
||||||
|
"shutdown: can use \"-n\" for halt or reboot only.\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell users what we're gonna do. */
|
||||||
|
switch(down_level[0]) {
|
||||||
|
case '0':
|
||||||
|
strcpy(newstate, "for system halt");
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
strcpy(newstate, "for reboot");
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
strcpy(newstate, "to maintenance mode");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprintf(newstate, "to runlevel %s", down_level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new PID file. */
|
||||||
|
unlink(SDPID);
|
||||||
|
umask(022);
|
||||||
|
if ((fp = fopen(SDPID, "w")) != NULL) {
|
||||||
|
fprintf(fp, "%d\n", getpid());
|
||||||
|
fclose(fp);
|
||||||
|
} else if (errno != EROFS)
|
||||||
|
fprintf(stderr, "shutdown: warning: cannot open %s\n", SDPID);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Catch some common signals.
|
||||||
|
*/
|
||||||
|
signal(SIGQUIT, SIG_IGN);
|
||||||
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
signal(SIGHUP, SIG_IGN);
|
||||||
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
signal(SIGTTIN, SIG_IGN);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = stopit;
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
|
||||||
|
/* Go to the root directory */
|
||||||
|
chdir("/");
|
||||||
|
if (fastboot) close(open(FASTBOOT, O_CREAT | O_RDWR, 0644));
|
||||||
|
if (forcefsck) close(open(FORCEFSCK, O_CREAT | O_RDWR, 0644));
|
||||||
|
|
||||||
|
/* Alias now and take care of old '+mins' notation. */
|
||||||
|
if (!strcmp(when, "now")) strcpy(when, "0");
|
||||||
|
if (when[0] == '+') when++;
|
||||||
|
|
||||||
|
/* Decode shutdown time. */
|
||||||
|
for (sp = when; *sp; sp++) {
|
||||||
|
if (*sp != ':' && (*sp < '0' || *sp > '9'))
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
if (strchr(when, ':') == NULL) {
|
||||||
|
/* Time in minutes. */
|
||||||
|
wt = atoi(when);
|
||||||
|
if (wt == 0 && when[0] != '0') usage();
|
||||||
|
} else {
|
||||||
|
/* Time in hh:mm format. */
|
||||||
|
if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
|
||||||
|
if (hours > 23 || mins > 59) usage();
|
||||||
|
time(&t);
|
||||||
|
lt = localtime(&t);
|
||||||
|
wt = (60*hours + mins) - (60*lt->tm_hour + lt->tm_min);
|
||||||
|
if (wt < 0) wt += 1440;
|
||||||
|
}
|
||||||
|
/* Shutdown NOW if time == 0 */
|
||||||
|
if (wt == 0) shutdown(halttype);
|
||||||
|
|
||||||
|
/* Give warnings on regular intervals and finally shutdown. */
|
||||||
|
if (wt < 15 && !needwarning(wt)) warn(wt);
|
||||||
|
while(wt) {
|
||||||
|
if (wt <= 5 && !didnolog) {
|
||||||
|
donologin(wt);
|
||||||
|
didnolog++;
|
||||||
|
}
|
||||||
|
if (needwarning(wt)) warn(wt);
|
||||||
|
hardsleep(60);
|
||||||
|
wt--;
|
||||||
|
}
|
||||||
|
shutdown(halttype);
|
||||||
|
|
||||||
|
return 0; /* Never happens */
|
||||||
|
}
|
505
src/sulogin.c
Normal file
505
src/sulogin.c
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
* sulogin This program gives Linux machines a reasonable
|
||||||
|
* secure way to boot single user. It forces the
|
||||||
|
* user to supply the root password before a
|
||||||
|
* shell is started.
|
||||||
|
*
|
||||||
|
* If there is a shadow password file and the
|
||||||
|
* encrypted root password is "x" the shadow
|
||||||
|
* password will be used.
|
||||||
|
*
|
||||||
|
* Version: @(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998-2003 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <shadow.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
# include <crypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
# include <selinux/selinux.h>
|
||||||
|
# include <selinux/get_context_list.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CHECK_DES 1
|
||||||
|
#define CHECK_MD5 1
|
||||||
|
|
||||||
|
#define F_PASSWD "/etc/passwd"
|
||||||
|
#define F_SHADOW "/etc/shadow"
|
||||||
|
#define BINSH "/bin/sh"
|
||||||
|
#define STATICSH "/bin/sash"
|
||||||
|
|
||||||
|
char *Version = "@(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl";
|
||||||
|
|
||||||
|
int timeout = 0;
|
||||||
|
int profile = 0;
|
||||||
|
|
||||||
|
#ifndef IUCLC
|
||||||
|
# define IUCLC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Fix the tty modes and set reasonable defaults.
|
||||||
|
* (I'm not sure if this is needed under Linux, but..)
|
||||||
|
*/
|
||||||
|
void fixtty(void)
|
||||||
|
{
|
||||||
|
struct termios tty;
|
||||||
|
|
||||||
|
tcgetattr(0, &tty);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set or adjust tty modes.
|
||||||
|
*/
|
||||||
|
tty.c_iflag &= ~(INLCR|IGNCR|IUCLC);
|
||||||
|
tty.c_iflag |= ICRNL;
|
||||||
|
tty.c_oflag &= ~(OCRNL|OLCUC|ONOCR|ONLRET|OFILL);
|
||||||
|
tty.c_oflag |= OPOST|ONLCR;
|
||||||
|
tty.c_cflag |= CLOCAL;
|
||||||
|
tty.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the most important characters */
|
||||||
|
*/
|
||||||
|
tty.c_cc[VINTR] = 3;
|
||||||
|
tty.c_cc[VQUIT] = 28;
|
||||||
|
tty.c_cc[VERASE] = 127;
|
||||||
|
tty.c_cc[VKILL] = 24;
|
||||||
|
tty.c_cc[VEOF] = 4;
|
||||||
|
tty.c_cc[VTIME] = 0;
|
||||||
|
tty.c_cc[VMIN] = 1;
|
||||||
|
tty.c_cc[VSTART] = 17;
|
||||||
|
tty.c_cc[VSTOP] = 19;
|
||||||
|
tty.c_cc[VSUSP] = 26;
|
||||||
|
|
||||||
|
tcsetattr(0, TCSANOW, &tty);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called at timeout.
|
||||||
|
*/
|
||||||
|
void alrm_handler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if an encrypted password is valid. The encrypted
|
||||||
|
* password is checked for traditional-style DES and
|
||||||
|
* FreeBSD-style MD5 encryption.
|
||||||
|
*/
|
||||||
|
int valid(char *pass)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (pass[0] == 0) return 1;
|
||||||
|
#if CHECK_MD5
|
||||||
|
/*
|
||||||
|
* 3 bytes for the signature $1$
|
||||||
|
* up to 8 bytes for the salt
|
||||||
|
* $
|
||||||
|
* the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
|
||||||
|
*/
|
||||||
|
if (strncmp(pass, "$1$", 3) == 0) {
|
||||||
|
for(s = pass + 3; *s && *s != '$'; s++)
|
||||||
|
;
|
||||||
|
if (*s++ != '$') return 0;
|
||||||
|
len = strlen(s);
|
||||||
|
if (len < 22 || len > 24) return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if CHECK_DES
|
||||||
|
if (strlen(pass) != 13) return 0;
|
||||||
|
for (s = pass; *s; s++) {
|
||||||
|
if ((*s < '0' || *s > '9') &&
|
||||||
|
(*s < 'a' || *s > 'z') &&
|
||||||
|
(*s < 'A' || *s > 'Z') &&
|
||||||
|
*s != '.' && *s != '/') return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set a variable if the value is not NULL.
|
||||||
|
*/
|
||||||
|
void set(char **var, char *val)
|
||||||
|
{
|
||||||
|
if (val) *var = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the root password entry.
|
||||||
|
*/
|
||||||
|
struct passwd *getrootpwent(int try_manually)
|
||||||
|
{
|
||||||
|
static struct passwd pwd;
|
||||||
|
struct passwd *pw;
|
||||||
|
struct spwd *spw;
|
||||||
|
FILE *fp;
|
||||||
|
static char line[256];
|
||||||
|
static char sline[256];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, we try to get the password the standard
|
||||||
|
* way using normal library calls.
|
||||||
|
*/
|
||||||
|
if ((pw = getpwnam("root")) &&
|
||||||
|
!strcmp(pw->pw_passwd, "x") &&
|
||||||
|
(spw = getspnam("root")))
|
||||||
|
pw->pw_passwd = spw->sp_pwdp;
|
||||||
|
if (pw || !try_manually) return pw;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we come here, we could not retrieve the root
|
||||||
|
* password through library calls and we try to
|
||||||
|
* read the password and shadow files manually.
|
||||||
|
*/
|
||||||
|
pwd.pw_name = "root";
|
||||||
|
pwd.pw_passwd = "";
|
||||||
|
pwd.pw_gecos = "Super User";
|
||||||
|
pwd.pw_dir = "/";
|
||||||
|
pwd.pw_shell = "";
|
||||||
|
pwd.pw_uid = 0;
|
||||||
|
pwd.pw_gid = 0;
|
||||||
|
|
||||||
|
if ((fp = fopen(F_PASSWD, "r")) == NULL) {
|
||||||
|
perror(F_PASSWD);
|
||||||
|
return &pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find root in the password file.
|
||||||
|
*/
|
||||||
|
while((p = fgets(line, 256, fp)) != NULL) {
|
||||||
|
if (strncmp(line, "root:", 5) != 0)
|
||||||
|
continue;
|
||||||
|
p += 5;
|
||||||
|
set(&pwd.pw_passwd, strsep(&p, ":"));
|
||||||
|
(void)strsep(&p, ":");
|
||||||
|
(void)strsep(&p, ":");
|
||||||
|
set(&pwd.pw_gecos, strsep(&p, ":"));
|
||||||
|
set(&pwd.pw_dir, strsep(&p, ":"));
|
||||||
|
set(&pwd.pw_shell, strsep(&p, "\n"));
|
||||||
|
p = line;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the encrypted password is valid
|
||||||
|
* or not found, return.
|
||||||
|
*/
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
|
||||||
|
return &pwd;
|
||||||
|
}
|
||||||
|
if (valid(pwd.pw_passwd)) return &pwd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The password is invalid. If there is a
|
||||||
|
* shadow password, try it.
|
||||||
|
*/
|
||||||
|
strcpy(pwd.pw_passwd, "");
|
||||||
|
if ((fp = fopen(F_SHADOW, "r")) == NULL) {
|
||||||
|
fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
|
||||||
|
return &pwd;
|
||||||
|
}
|
||||||
|
while((p = fgets(sline, 256, fp)) != NULL) {
|
||||||
|
if (strncmp(sline, "root:", 5) != 0)
|
||||||
|
continue;
|
||||||
|
p += 5;
|
||||||
|
set(&pwd.pw_passwd, strsep(&p, ":"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the password is still invalid,
|
||||||
|
* NULL it, and return.
|
||||||
|
*/
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
|
||||||
|
strcpy(pwd.pw_passwd, "");
|
||||||
|
}
|
||||||
|
if (!valid(pwd.pw_passwd)) {
|
||||||
|
fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
|
||||||
|
strcpy(pwd.pw_passwd, ""); }
|
||||||
|
return &pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ask for the password. Note that there is no
|
||||||
|
* default timeout as we normally skip this during boot.
|
||||||
|
*/
|
||||||
|
char *getpasswd(char *crypted)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
struct termios old, tty;
|
||||||
|
static char pass[128];
|
||||||
|
char *ret = pass;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (crypted[0])
|
||||||
|
printf("Give root password for maintenance\n");
|
||||||
|
else
|
||||||
|
printf("Press enter for maintenance\n");
|
||||||
|
printf("(or type Control-D to continue): ");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
tcgetattr(0, &old);
|
||||||
|
tcgetattr(0, &tty);
|
||||||
|
tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
|
||||||
|
tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
|
||||||
|
tcsetattr(0, TCSANOW, &tty);
|
||||||
|
|
||||||
|
pass[sizeof(pass) - 1] = 0;
|
||||||
|
|
||||||
|
sa.sa_handler = alrm_handler;
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigaction(SIGALRM, &sa, NULL);
|
||||||
|
if (timeout) alarm(timeout);
|
||||||
|
|
||||||
|
if (read(0, pass, sizeof(pass) - 1) <= 0)
|
||||||
|
ret = NULL;
|
||||||
|
else {
|
||||||
|
for(i = 0; i < sizeof(pass) && pass[i]; i++)
|
||||||
|
if (pass[i] == '\r' || pass[i] == '\n') {
|
||||||
|
pass[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alarm(0);
|
||||||
|
tcsetattr(0, TCSANOW, &old);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Password was OK, execute a shell.
|
||||||
|
*/
|
||||||
|
void sushell(struct passwd *pwd)
|
||||||
|
{
|
||||||
|
char shell[128];
|
||||||
|
char home[128];
|
||||||
|
char *p;
|
||||||
|
char *sushell;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set directory and shell.
|
||||||
|
*/
|
||||||
|
(void)chdir(pwd->pw_dir);
|
||||||
|
if ((p = getenv("SUSHELL")) != NULL)
|
||||||
|
sushell = p;
|
||||||
|
else if ((p = getenv("sushell")) != NULL)
|
||||||
|
sushell = p;
|
||||||
|
else {
|
||||||
|
if (pwd->pw_shell[0])
|
||||||
|
sushell = pwd->pw_shell;
|
||||||
|
else
|
||||||
|
sushell = BINSH;
|
||||||
|
}
|
||||||
|
if ((p = strrchr(sushell, '/')) == NULL)
|
||||||
|
p = sushell;
|
||||||
|
else
|
||||||
|
p++;
|
||||||
|
snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set some important environment variables.
|
||||||
|
*/
|
||||||
|
getcwd(home, sizeof(home));
|
||||||
|
setenv("HOME", home, 1);
|
||||||
|
setenv("LOGNAME", "root", 1);
|
||||||
|
setenv("USER", "root", 1);
|
||||||
|
if (!profile)
|
||||||
|
setenv("SHLVL","0",1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to execute a shell.
|
||||||
|
*/
|
||||||
|
setenv("SHELL", sushell, 1);
|
||||||
|
signal(SIGINT, SIG_DFL);
|
||||||
|
signal(SIGTSTP, SIG_DFL);
|
||||||
|
signal(SIGQUIT, SIG_DFL);
|
||||||
|
#ifdef WITH_SELINUX
|
||||||
|
if (is_selinux_enabled > 0) {
|
||||||
|
security_context_t scon=NULL;
|
||||||
|
char *seuser=NULL;
|
||||||
|
char *level=NULL;
|
||||||
|
if (getseuserbyname("root", &seuser, &level) == 0)
|
||||||
|
if (get_default_context_with_level(seuser, level, 0, &scon) > 0) {
|
||||||
|
if (setexeccon(scon) != 0)
|
||||||
|
fprintf(stderr, "setexeccon faile\n");
|
||||||
|
freecon(scon);
|
||||||
|
}
|
||||||
|
free(seuser);
|
||||||
|
free(level);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
execl(sushell, shell, NULL);
|
||||||
|
perror(sushell);
|
||||||
|
|
||||||
|
setenv("SHELL", BINSH, 1);
|
||||||
|
execl(BINSH, profile ? "-sh" : "sh", NULL);
|
||||||
|
perror(BINSH);
|
||||||
|
|
||||||
|
/* Fall back to staticly linked shell if both the users shell
|
||||||
|
and /bin/sh failed to execute. */
|
||||||
|
setenv("SHELL", STATICSH, 1);
|
||||||
|
execl(STATICSH, STATICSH, NULL);
|
||||||
|
perror(STATICSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *tty = NULL;
|
||||||
|
char *p;
|
||||||
|
struct passwd *pwd;
|
||||||
|
int c, fd = -1;
|
||||||
|
int opt_e = 0;
|
||||||
|
pid_t pid, pgrp, ppgrp, ttypgrp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we have a timeout flag.
|
||||||
|
*/
|
||||||
|
opterr = 0;
|
||||||
|
while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {
|
||||||
|
case 't':
|
||||||
|
timeout = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
profile = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
opt_e = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
/* Do not exit! */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geteuid() != 0) {
|
||||||
|
fprintf(stderr, "sulogin: only root can run sulogin.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we need to open an other tty device.
|
||||||
|
*/
|
||||||
|
signal(SIGINT, SIG_IGN);
|
||||||
|
signal(SIGQUIT, SIG_IGN);
|
||||||
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
if (optind < argc) tty = argv[optind];
|
||||||
|
if (tty) {
|
||||||
|
if ((fd = open(tty, O_RDWR)) < 0) {
|
||||||
|
perror(tty);
|
||||||
|
} else if (!isatty(fd)) {
|
||||||
|
fprintf(stderr, "%s: not a tty\n", tty);
|
||||||
|
close(fd);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only go through this trouble if the new
|
||||||
|
* tty doesn't fall in this process group.
|
||||||
|
*/
|
||||||
|
pid = getpid();
|
||||||
|
pgrp = getpgid(0);
|
||||||
|
ppgrp = getpgid(getppid());
|
||||||
|
ioctl(fd, TIOCGPGRP, &ttypgrp);
|
||||||
|
|
||||||
|
if (pgrp != ttypgrp && ppgrp != ttypgrp) {
|
||||||
|
if (pid != getsid(0)) {
|
||||||
|
if (pid == getpgid(0))
|
||||||
|
setpgid(0, getpgid(getppid()));
|
||||||
|
setsid();
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGHUP, SIG_IGN);
|
||||||
|
ioctl(0, TIOCNOTTY, (char *)1);
|
||||||
|
signal(SIGHUP, SIG_DFL);
|
||||||
|
close(0);
|
||||||
|
close(1);
|
||||||
|
close(2);
|
||||||
|
close(fd);
|
||||||
|
fd = open(tty, O_RDWR);
|
||||||
|
ioctl(0, TIOCSCTTY, (char *)1);
|
||||||
|
dup(fd);
|
||||||
|
dup(fd);
|
||||||
|
} else
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
} else if (getpid() == 1) {
|
||||||
|
/* We are init. We hence need to set a session anyway */
|
||||||
|
setsid();
|
||||||
|
if (ioctl(0, TIOCSCTTY, (char *)1))
|
||||||
|
perror("ioctl(TIOCSCTTY)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the root password.
|
||||||
|
*/
|
||||||
|
if ((pwd = getrootpwent(opt_e)) == NULL) {
|
||||||
|
fprintf(stderr, "sulogin: cannot open password database!\n");
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ask for the password.
|
||||||
|
*/
|
||||||
|
while(pwd) {
|
||||||
|
if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
|
||||||
|
if (pwd->pw_passwd[0] == 0 ||
|
||||||
|
strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
|
||||||
|
sushell(pwd);
|
||||||
|
printf("Login incorrect.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User pressed Control-D.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
224
src/utmp.c
Normal file
224
src/utmp.c
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* utmp.c Routines to read/write the utmp and wtmp files.
|
||||||
|
* Basically just wrappers around the library routines.
|
||||||
|
*
|
||||||
|
* Version: @(#)utmp.c 2.77 09-Jun-1999 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
|
||||||
|
#include "init.h"
|
||||||
|
#include "initreq.h"
|
||||||
|
#include "paths.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
# if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) && defined(__powerpc__)
|
||||||
|
# define HAVE_UPDWTMP 0
|
||||||
|
# else
|
||||||
|
# define HAVE_UPDWTMP 1
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define HAVE_UPDWTMP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log an event in the wtmp file (reboot, runlevel)
|
||||||
|
*/
|
||||||
|
void write_wtmp(
|
||||||
|
char *user, /* name of user */
|
||||||
|
char *id, /* inittab ID */
|
||||||
|
int pid, /* PID of process */
|
||||||
|
int type, /* TYPE of entry */
|
||||||
|
char *line) /* Which line is this */
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct utmp utmp;
|
||||||
|
struct utsname uname_buf;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to open the wtmp file. Note that we even try
|
||||||
|
* this if we have updwtmp() so we can see if the
|
||||||
|
* wtmp file is accessible.
|
||||||
|
*/
|
||||||
|
if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND)) < 0) return;
|
||||||
|
|
||||||
|
#ifdef INIT_MAIN
|
||||||
|
/*
|
||||||
|
* Note if we are going to write a boot record.
|
||||||
|
*/
|
||||||
|
if (type == BOOT_TIME) wrote_wtmp_reboot++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we need to write a reboot record. The reason that
|
||||||
|
* we are being so paranoid is that when we first tried to
|
||||||
|
* write the reboot record, /var was possibly not mounted
|
||||||
|
* yet. As soon as we can open WTMP we write a delayed boot record.
|
||||||
|
*/
|
||||||
|
if (wrote_wtmp_reboot == 0 && type != BOOT_TIME)
|
||||||
|
write_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Zero the fields and enter new fields.
|
||||||
|
*/
|
||||||
|
memset(&utmp, 0, sizeof(utmp));
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
utmp.ut_tv.tv_sec = tv.tv_sec;
|
||||||
|
utmp.ut_tv.tv_usec = tv.tv_usec;
|
||||||
|
#else
|
||||||
|
time(&utmp.ut_time);
|
||||||
|
#endif
|
||||||
|
utmp.ut_pid = pid;
|
||||||
|
utmp.ut_type = type;
|
||||||
|
strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
|
||||||
|
strncpy(utmp.ut_id , id , sizeof(utmp.ut_id ));
|
||||||
|
strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
|
||||||
|
|
||||||
|
/* Put the OS version in place of the hostname */
|
||||||
|
if (uname(&uname_buf) == 0)
|
||||||
|
strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host));
|
||||||
|
|
||||||
|
#if HAVE_UPDWTMP
|
||||||
|
updwtmp(WTMP_FILE, &utmp);
|
||||||
|
#else
|
||||||
|
write(fd, (char *)&utmp, sizeof(utmp));
|
||||||
|
#endif
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write an entry to the UTMP file. For DEAD_PROCESS, put
|
||||||
|
* the previous ut_line into oldline if oldline != NULL.
|
||||||
|
*/
|
||||||
|
static void write_utmp(
|
||||||
|
char *user, /* name of user */
|
||||||
|
char *id, /* inittab ID */
|
||||||
|
int pid, /* PID of process */
|
||||||
|
int type, /* TYPE of entry */
|
||||||
|
char *line, /* LINE if used. */
|
||||||
|
char *oldline) /* Line of old utmp entry. */
|
||||||
|
{
|
||||||
|
struct utmp utmp;
|
||||||
|
struct utmp tmp;
|
||||||
|
struct utmp *utmptr;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't do much if UTMP_FILE is not present.
|
||||||
|
*/
|
||||||
|
if (access(UTMP_FILE, F_OK) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef INIT_MAIN
|
||||||
|
/*
|
||||||
|
* Note if we are going to write a boot record.
|
||||||
|
*/
|
||||||
|
if (type == BOOT_TIME) wrote_utmp_reboot++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we need to write a reboot record. The reason that
|
||||||
|
* we are being so paranoid is that when we first tried to
|
||||||
|
* write the reboot record, /var was possibly not mounted
|
||||||
|
* yet. As soon as we can open WTMP we write a delayed boot record.
|
||||||
|
*/
|
||||||
|
if (wrote_utmp_reboot == 0 && type != BOOT_TIME)
|
||||||
|
write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill out an utmp struct.
|
||||||
|
*/
|
||||||
|
memset(&utmp, 0, sizeof(utmp));
|
||||||
|
utmp.ut_type = type;
|
||||||
|
utmp.ut_pid = pid;
|
||||||
|
strncpy(utmp.ut_id, id, sizeof(utmp.ut_id));
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
utmp.ut_tv.tv_sec = tv.tv_sec;
|
||||||
|
utmp.ut_tv.tv_usec = tv.tv_usec;
|
||||||
|
#else
|
||||||
|
time(&utmp.ut_time);
|
||||||
|
#endif
|
||||||
|
strncpy(utmp.ut_user, user, UT_NAMESIZE);
|
||||||
|
if (line) strncpy(utmp.ut_line, line, UT_LINESIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We might need to find the existing entry first, to
|
||||||
|
* find the tty of the process (for wtmp accounting).
|
||||||
|
*/
|
||||||
|
if (type == DEAD_PROCESS) {
|
||||||
|
/*
|
||||||
|
* Find existing entry for the tty line.
|
||||||
|
*/
|
||||||
|
setutent();
|
||||||
|
tmp = utmp;
|
||||||
|
if ((utmptr = getutid(&tmp)) != NULL) {
|
||||||
|
strncpy(utmp.ut_line, utmptr->ut_line, UT_LINESIZE);
|
||||||
|
if (oldline)
|
||||||
|
strncpy(oldline, utmptr->ut_line, UT_LINESIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update existing utmp file.
|
||||||
|
*/
|
||||||
|
setutent();
|
||||||
|
pututline(&utmp);
|
||||||
|
endutent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a record to both utmp and wtmp.
|
||||||
|
*/
|
||||||
|
void write_utmp_wtmp(
|
||||||
|
char *user, /* name of user */
|
||||||
|
char *id, /* inittab ID */
|
||||||
|
int pid, /* PID of process */
|
||||||
|
int type, /* TYPE of entry */
|
||||||
|
char *line) /* LINE if used. */
|
||||||
|
{
|
||||||
|
char oldline[UT_LINESIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For backwards compatibility we just return
|
||||||
|
* if user == NULL (means : clean up utmp file).
|
||||||
|
*/
|
||||||
|
if (user == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
oldline[0] = 0;
|
||||||
|
write_utmp(user, id, pid, type, line, oldline);
|
||||||
|
write_wtmp(user, id, pid, type, line && line[0] ? line : oldline);
|
||||||
|
}
|
||||||
|
|
298
src/utmpdump.c
Normal file
298
src/utmpdump.c
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* utmpdump Simple program to dump UTMP and WTMP files in
|
||||||
|
* raw format, so they can be examined.
|
||||||
|
*
|
||||||
|
* Author: Miquel van Smoorenburg, <miquels@cistron.nl>
|
||||||
|
* Danek Duvall <duvall@alumni.princeton.edu>
|
||||||
|
*
|
||||||
|
* Version: @(#)utmpdump 2.79 12-Sep-2000
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2000 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* Additional Copyright on this file 1998 Danek Duvall.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "oldutmp.h"
|
||||||
|
|
||||||
|
struct utmp
|
||||||
|
oldtonew(struct oldutmp src)
|
||||||
|
{
|
||||||
|
struct utmp dest;
|
||||||
|
|
||||||
|
memset(&dest, 0, sizeof dest);
|
||||||
|
dest.ut_type = src.ut_type;
|
||||||
|
dest.ut_pid = src.ut_pid;
|
||||||
|
dest.ut_time = src.ut_oldtime;
|
||||||
|
dest.ut_addr = src.ut_oldaddr;
|
||||||
|
strncpy(dest.ut_id, src.ut_id, 4);
|
||||||
|
strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
|
||||||
|
strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
|
||||||
|
strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct oldutmp
|
||||||
|
newtoold(struct utmp src)
|
||||||
|
{
|
||||||
|
struct oldutmp dest;
|
||||||
|
|
||||||
|
memset(&dest, 0, sizeof dest);
|
||||||
|
dest.ut_type = src.ut_type;
|
||||||
|
dest.ut_pid = src.ut_pid;
|
||||||
|
dest.ut_oldtime = src.ut_time;
|
||||||
|
dest.ut_oldaddr = src.ut_addr;
|
||||||
|
strncpy(dest.ut_id, src.ut_id, 4);
|
||||||
|
strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
|
||||||
|
strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
|
||||||
|
strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
timetostr(const time_t time)
|
||||||
|
{
|
||||||
|
static char s[29]; /* [Sun Sep 01 00:00:00 1998 PST] */
|
||||||
|
|
||||||
|
if (time != 0)
|
||||||
|
strftime(s, 29, "%a %b %d %T %Y %Z", localtime(&time));
|
||||||
|
else
|
||||||
|
s[0] = '\0';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t
|
||||||
|
strtotime(const char *s_time)
|
||||||
|
{
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
memset(&tm, '\0', sizeof(struct tm));
|
||||||
|
|
||||||
|
if (s_time[0] == ' ' || s_time[0] == '\0')
|
||||||
|
return (time_t)0;
|
||||||
|
|
||||||
|
strptime(s_time, "%a %b %d %T %Y", &tm);
|
||||||
|
|
||||||
|
/* Cheesy way of checking for DST */
|
||||||
|
if (s_time[26] == 'D')
|
||||||
|
tm.tm_isdst = 1;
|
||||||
|
|
||||||
|
return mktime(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define cleanse(x) xcleanse(x, sizeof(x))
|
||||||
|
void
|
||||||
|
xcleanse(char *s, int len)
|
||||||
|
{
|
||||||
|
for ( ; *s && len-- > 0; s++)
|
||||||
|
if (!isprint(*s) || *s == '[' || *s == ']')
|
||||||
|
*s = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unspace(char *s, int len)
|
||||||
|
{
|
||||||
|
while (*s && *s != ' ' && len--)
|
||||||
|
++s;
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_utline(struct utmp ut)
|
||||||
|
{
|
||||||
|
char *addr_string, *time_string;
|
||||||
|
struct in_addr in;
|
||||||
|
|
||||||
|
in.s_addr = ut.ut_addr;
|
||||||
|
addr_string = inet_ntoa(in);
|
||||||
|
time_string = timetostr(ut.ut_time);
|
||||||
|
cleanse(ut.ut_id);
|
||||||
|
cleanse(ut.ut_user);
|
||||||
|
cleanse(ut.ut_line);
|
||||||
|
cleanse(ut.ut_host);
|
||||||
|
|
||||||
|
/* pid id user line host addr time */
|
||||||
|
printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15.15s] [%-28.28s]\n",
|
||||||
|
ut.ut_type, ut.ut_pid, ut.ut_id, 8, UT_NAMESIZE, ut.ut_user,
|
||||||
|
12, UT_LINESIZE, ut.ut_line, 20, UT_HOSTSIZE, ut.ut_host,
|
||||||
|
addr_string, time_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dump(FILE *fp, int forever, int oldfmt)
|
||||||
|
{
|
||||||
|
struct utmp ut;
|
||||||
|
struct oldutmp uto;
|
||||||
|
|
||||||
|
if (forever)
|
||||||
|
fseek(fp, -10 * (oldfmt ? sizeof uto : sizeof ut), SEEK_END);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (oldfmt)
|
||||||
|
while (fread(&uto, sizeof uto, 1, fp) == 1)
|
||||||
|
print_utline(oldtonew(uto));
|
||||||
|
else
|
||||||
|
while (fread(&ut, sizeof ut, 1, fp) == 1)
|
||||||
|
print_utline(ut);
|
||||||
|
if (forever) sleep(1);
|
||||||
|
} while (forever);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function won't work properly if there's a ']' or a ' ' in the real
|
||||||
|
* token. Thankfully, this should never happen. */
|
||||||
|
int
|
||||||
|
gettok(char *line, char *dest, int size, int eatspace)
|
||||||
|
{
|
||||||
|
int bpos, epos, eaten;
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
bpos = strchr(line, '[') - line;
|
||||||
|
if (bpos < 0) {
|
||||||
|
fprintf(stderr, "Extraneous newline in file. Exiting.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
line += 1 + bpos;
|
||||||
|
|
||||||
|
epos = strchr(line, ']') - line;
|
||||||
|
if (epos < 0) {
|
||||||
|
fprintf(stderr, "Extraneous newline in file. Exiting.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
line[epos] = '\0';
|
||||||
|
|
||||||
|
eaten = bpos + epos + 1;
|
||||||
|
|
||||||
|
if (eatspace)
|
||||||
|
if ((t = strchr(line, ' ')))
|
||||||
|
*t = 0;
|
||||||
|
|
||||||
|
strncpy(dest, line, size);
|
||||||
|
|
||||||
|
return eaten + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
undump(FILE *fp, int forever, int oldfmt)
|
||||||
|
{
|
||||||
|
struct utmp ut;
|
||||||
|
struct oldutmp uto;
|
||||||
|
char s_addr[16], s_time[29], *linestart, *line;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
line = linestart = malloc(1024 * sizeof *linestart);
|
||||||
|
s_addr[15] = 0;
|
||||||
|
s_time[28] = 0;
|
||||||
|
|
||||||
|
while(fgets(linestart, 1023, fp))
|
||||||
|
{
|
||||||
|
line = linestart;
|
||||||
|
memset(&ut, '\0', sizeof(ut));
|
||||||
|
sscanf(line, "[%hd] [%d] [%4c] ", &ut.ut_type, &ut.ut_pid, ut.ut_id);
|
||||||
|
|
||||||
|
line += 19;
|
||||||
|
line += gettok(line, ut.ut_user, sizeof(ut.ut_user), 1);
|
||||||
|
line += gettok(line, ut.ut_line, sizeof(ut.ut_line), 1);
|
||||||
|
line += gettok(line, ut.ut_host, sizeof(ut.ut_host), 1);
|
||||||
|
line += gettok(line, s_addr, sizeof(s_addr)-1, 1);
|
||||||
|
line += gettok(line, s_time, sizeof(s_time)-1, 0);
|
||||||
|
|
||||||
|
ut.ut_addr = inet_addr(s_addr);
|
||||||
|
ut.ut_time = strtotime(s_time);
|
||||||
|
|
||||||
|
if (oldfmt) {
|
||||||
|
uto = newtoold(ut);
|
||||||
|
fwrite(&uto, sizeof(uto), 1, stdout);
|
||||||
|
} else
|
||||||
|
fwrite(&ut, sizeof(ut), 1, stdout);
|
||||||
|
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(linestart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(int result)
|
||||||
|
{
|
||||||
|
printf("Usage: utmpdump [ -froh ] [ filename ]\n");
|
||||||
|
exit(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
FILE *fp;
|
||||||
|
int reverse = 0, forever = 0, oldfmt = 0;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "froh")) != EOF) {
|
||||||
|
switch (c) {
|
||||||
|
case 'r':
|
||||||
|
reverse = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
forever = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
oldfmt = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
usage(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc) {
|
||||||
|
fprintf(stderr, "Utmp %sdump of %s\n", reverse ? "un" : "", argv[optind]);
|
||||||
|
if ((fp = fopen(argv[optind], "r")) == NULL) {
|
||||||
|
perror("Unable to open file");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Utmp %sdump of stdin\n", reverse ? "un" : "");
|
||||||
|
fp = stdin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
undump(fp, forever, oldfmt);
|
||||||
|
else
|
||||||
|
dump(fp, forever, oldfmt);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
123
src/wall.c
Normal file
123
src/wall.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* wall.c Write to all users logged in.
|
||||||
|
*
|
||||||
|
* Usage: wall [text]
|
||||||
|
*
|
||||||
|
* Version: @(#)wall 2.79 12-Sep-2000 miquels@cistron.nl
|
||||||
|
*
|
||||||
|
* This file is part of the sysvinit suite,
|
||||||
|
* Copyright (C) 1991-2000 Miquel van Smoorenburg.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
|
||||||
|
char *Version = "@(#) wall 2.79 12-Sep-2000 miquels@cistron.nl";
|
||||||
|
#define MAXLEN 4096
|
||||||
|
#define MAXLINES 20
|
||||||
|
|
||||||
|
extern void wall(char *, int, int);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char buf[MAXLEN];
|
||||||
|
char line[83];
|
||||||
|
int i, f, ch;
|
||||||
|
int len = 0;
|
||||||
|
int remote = 0;
|
||||||
|
char *p;
|
||||||
|
char *whoami;
|
||||||
|
struct passwd *pwd;
|
||||||
|
|
||||||
|
buf[0] = 0;
|
||||||
|
if ((pwd = getpwuid(getuid())) == NULL) {
|
||||||
|
if (getuid() == 0)
|
||||||
|
whoami = "root";
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "You don't exist. Go away.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
whoami = pwd->pw_name;
|
||||||
|
|
||||||
|
while((ch = getopt(argc, argv, "n")) != EOF)
|
||||||
|
switch(ch) {
|
||||||
|
case 'n':
|
||||||
|
/*
|
||||||
|
* Undocumented option for suppressing
|
||||||
|
* banner from rpc.rwalld. Only works if
|
||||||
|
* we are root or if we're NOT setgid.
|
||||||
|
*/
|
||||||
|
if (geteuid() != 0 && getgid() != getegid()) {
|
||||||
|
fprintf(stderr, "wall -n: not priviliged\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
remote = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "usage: wall [message]\n");
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((argc - optind) > 0) {
|
||||||
|
for(f = optind; f < argc; f++) {
|
||||||
|
len += strlen(argv[f]) + 1;
|
||||||
|
if (len >= MAXLEN-2) break;
|
||||||
|
strcat(buf, argv[f]);
|
||||||
|
if (f < argc-1) strcat(buf, " ");
|
||||||
|
}
|
||||||
|
strcat(buf, "\r\n");
|
||||||
|
} else {
|
||||||
|
while(fgets(line, 80, stdin)) {
|
||||||
|
/*
|
||||||
|
* Make sure that line ends in \r\n
|
||||||
|
*/
|
||||||
|
for(p = line; *p && *p != '\r' && *p != '\n'; p++)
|
||||||
|
;
|
||||||
|
strcpy(p, "\r\n");
|
||||||
|
len += strlen(line);
|
||||||
|
if (len >= MAXLEN) break;
|
||||||
|
strcat(buf, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (p = buf; *p; p++) {
|
||||||
|
if (*p == '\n' && i++ > MAXLINES) {
|
||||||
|
*++p = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openlog("wall", LOG_PID, LOG_USER);
|
||||||
|
syslog(LOG_INFO, "wall: user %s broadcasted %d lines (%d chars)",
|
||||||
|
whoami, i, strlen(buf));
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
unsetenv("TZ");
|
||||||
|
wall(buf, 0, remote);
|
||||||
|
|
||||||
|
/*NOTREACHED*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user