Import Upstream version 2.96
This commit is contained in:
commit
c6e5b365de
|
@ -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.
|
|
@ -0,0 +1,22 @@
|
|||
Sysvinit is Copyright (C) 1991-2004 Miquel van Smoorenburg
|
||||
Updated Copyright (C) 2018 Jesse Smith
|
||||
|
||||
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
|
||||
|
||||
On Debian GNU/Linux systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
Send patches to sysvinit-devel@nongnu.org
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
PACKAGE=sysvinit
|
||||
VERSION=$(shell sed -rn '1s/.*[[:blank:]]\((.*)\)[[:blank:]].*/\1/p' doc/Changelog)
|
||||
|
||||
all install clean distclean:
|
||||
@rm -f $(PACKAGE)-$(VERSION).tar.xz $(PACKAGE)-$(VERSION).tar.xz.sig
|
||||
$(MAKE) VERSION=$(VERSION) -C src $@
|
||||
|
||||
GITLOGIN=$(shell git remote -v | head -n 1 | cut -f 1 -d '@' | sed 's/origin\t//g')
|
||||
override TMP:=$(shell mktemp -du $(VERSION).XXXXXXXX)
|
||||
override TARBALL:=$(TMP)/$(PACKAGE)-$(VERSION).tar.xz
|
||||
override SFTPBATCH:=$(TMP)/$(VERSION)-sftpbatch
|
||||
SOURCES=contrib COPYING COPYRIGHT doc Makefile man README src
|
||||
|
||||
dist: $(TARBALL).sig
|
||||
@cp $(TARBALL) .
|
||||
@cp $(TARBALL).sig .
|
||||
@echo "tarball $(PACKAGE)-$(VERSION).tar.xz ready"
|
||||
rm -rf $(TMP)
|
||||
|
||||
upload: $(SFTPBATCH)
|
||||
echo @sftp -b $< $(GITLOGIN)@dl.sv.nongnu.org:/releases/$(PACKAGE)
|
||||
rm -rf $(TMP)
|
||||
|
||||
$(SFTPBATCH): $(TARBALL).sig
|
||||
@echo progress > $@
|
||||
@echo put $(TARBALL) >> $@
|
||||
@echo chmod 664 $(notdir $(TARBALL)) >> $@
|
||||
@echo put $(TARBALL).sig >> $@
|
||||
@echo chmod 664 $(notdir $(TARBALL)).sig >> $@
|
||||
@echo rm $(PACKAGE)-latest.tar.bz2 >> $@
|
||||
@echo symlink $(notdir $(TARBALL)) $(PACKAGE)-latest.tar.bz2 >> $@
|
||||
@echo quit >> $@
|
||||
|
||||
$(TARBALL).sig: $(TARBALL)
|
||||
@gpg -q -ba --use-agent -o $@ $<
|
||||
|
||||
$(TARBALL): $(TMP)/$(PACKAGE)-$(VERSION)
|
||||
@tar --exclude=.git --owner=nobody --group=nogroup -cJf $@ -C $(TMP) $(PACKAGE)-$(VERSION)
|
||||
|
||||
$(TMP)/$(PACKAGE)-$(VERSION): distclean
|
||||
@mkdir -p $(TMP)/$(PACKAGE)-$(VERSION)
|
||||
@cp -R $(SOURCES) $(TMP)/$(PACKAGE)-$(VERSION)/
|
||||
@chmod -R a+r,u+w,og-w $@
|
||||
@find $@ -type d | xargs -r chmod a+rx,u+w,og-w
|
|
@ -0,0 +1,33 @@
|
|||
README for SysV init
|
||||
====================
|
||||
|
||||
SysV init is a classic initilization program (PID 1) for GNU/Linux and
|
||||
other UNIX/POSIX systems. It is designed to be small, simple and to
|
||||
stay out of the way.
|
||||
|
||||
Init is the parent (or grandparent) of all other processes on the
|
||||
system. It kicks off the starting of other system services and
|
||||
can act as a parent process to services which no longer have an
|
||||
active parent process.
|
||||
|
||||
SysV init uses the concept of runlevels. A runlevel is a configuration of the
|
||||
system which allows only a selected group of processes to exist.
|
||||
The processes spawned by init for each of these runlevels are defined in the
|
||||
/etc/inittab file. Init can be in one of eight runlevels. The runlevel is
|
||||
changed by the administrator running the telinit command which selects
|
||||
which runlevel we want to use.
|
||||
|
||||
More information on init, runlevels and switching between them can be found
|
||||
in the init manual page. (See "man init".)
|
||||
|
||||
contrib Unofficial stuff, add-on programs
|
||||
doc Documentation
|
||||
man Manual pages
|
||||
src Source code
|
||||
|
||||
For instructions on building and installing SysV init, please
|
||||
see the "doc/Install" file.
|
||||
|
||||
The project home is on https://savannah.nongnu.org/projects/sysvinit
|
||||
|
||||
Send patches to sysvinit-devel@nongnu.org .
|
|
@ -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.
|
||||
|
|
@ -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?
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Script to migrate sysvinit project source code from subversion to git.
|
||||
# Used february 2018.
|
||||
|
||||
authorsmap=$(tempfile)
|
||||
cat > $authorsmap <<EOF
|
||||
pere = Petter Reinholdtsen <pere@hungry.com>
|
||||
wfink = Werner Fink <werner@suse.de>
|
||||
EOF
|
||||
|
||||
for p in sysvinit startpar insserv; do
|
||||
git svn clone http://svn.savannah.nongnu.org/svn/sysvinit/$p \
|
||||
--authors-file=$authorsmap \
|
||||
--no-metadata \
|
||||
--tags=tags \
|
||||
--trunk=trunk \
|
||||
--prefix=$p/ \
|
||||
$p-git
|
||||
|
||||
(
|
||||
cd $p-git
|
||||
for tag in `git branch -r | grep "tags/" | sed "s/ $p\/tags\///"`; do
|
||||
git tag -a -m"Converting SVN tags" $tag refs/remotes/$p/tags/$tag
|
||||
done
|
||||
if [ "sysvinit" = "$p" ]; then
|
||||
remote=$p.git
|
||||
else
|
||||
remote=sysvinit/$p.git
|
||||
fi
|
||||
git remote add origin ssh://git.savannah.gnu.org:/srv/git/$remote
|
||||
)
|
||||
done
|
||||
rm $authorsmap
|
|
@ -0,0 +1,220 @@
|
|||
Index: src/init.sample
|
||||
===================================================================
|
||||
--- src/init.sample (revision 0)
|
||||
+++ src/init.sample (revision 0)
|
||||
@@ -0,0 +1,9 @@
|
||||
+#%PAM-1.0
|
||||
+#
|
||||
+# The PAM configuration file for /sbin/init
|
||||
+# Used for updating the lastlog logging file
|
||||
+#
|
||||
+auth sufficient pam_rootok.so
|
||||
+account include common-account
|
||||
+session include common-session
|
||||
+session requisite pam_lastlog.so silent
|
||||
Index: src/init.c
|
||||
===================================================================
|
||||
--- src/init.c (revision 56)
|
||||
+++ src/init.c (working copy)
|
||||
@@ -76,6 +76,10 @@
|
||||
#include "reboot.h"
|
||||
#include "set.h"
|
||||
|
||||
+#ifdef USE_PAM
|
||||
+extern void notify_pam_dead_session(const char *id);
|
||||
+#endif
|
||||
+
|
||||
#ifndef SIGPWR
|
||||
# define SIGPWR SIGUSR2
|
||||
#endif
|
||||
@@ -1129,6 +1133,9 @@
|
||||
}
|
||||
dup(f);
|
||||
dup(f);
|
||||
+#ifdef USE_PAM
|
||||
+ notify_pam_dead_session(ch->id);
|
||||
+#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1548,6 +1555,9 @@
|
||||
INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
|
||||
ch->pid, ch->id);
|
||||
ch->flags &= ~RUNNING;
|
||||
+#ifdef USE_PAM
|
||||
+ notify_pam_dead_session(ch->id);
|
||||
+#endif
|
||||
if (ch->process[0] != '+')
|
||||
write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
|
||||
}
|
||||
@@ -2009,6 +2019,9 @@
|
||||
if (ch->flags & ZOMBIE) {
|
||||
INITDBG(L_VB, "Child died, PID= %d", ch->pid);
|
||||
ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
|
||||
+#ifdef USE_PAM
|
||||
+ notify_pam_dead_session(ch->id);
|
||||
+#endif
|
||||
if (ch->process[0] != '+')
|
||||
write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
|
||||
}
|
||||
@@ -2453,6 +2466,9 @@
|
||||
if (ch->flags & ZOMBIE) {
|
||||
INITDBG(L_VB, "Child died, PID= %d", ch->pid);
|
||||
ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
|
||||
+#ifdef USE_PAM
|
||||
+ notify_pam_dead_session(ch->id);
|
||||
+#endif
|
||||
if (ch->process[0] != '+')
|
||||
write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
|
||||
}
|
||||
Index: src/utmp.c
|
||||
===================================================================
|
||||
--- src/utmp.c (revision 51)
|
||||
+++ src/utmp.c (working copy)
|
||||
@@ -34,10 +34,18 @@
|
||||
#include <string.h>
|
||||
#include <utmp.h>
|
||||
|
||||
+#if defined(USE_PAM) && defined(INIT_MAIN)
|
||||
+# include <security/pam_appl.h>
|
||||
+# include <security/pam_misc.h>
|
||||
+#endif
|
||||
+
|
||||
#include "init.h"
|
||||
#include "initreq.h"
|
||||
#include "paths.h"
|
||||
|
||||
+#ifndef _PATH_DEV
|
||||
+# define _PATH_DEV "/dev/"
|
||||
+#endif
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
# if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) && defined(__powerpc__)
|
||||
@@ -127,9 +135,9 @@
|
||||
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)
|
||||
+
|
||||
+ /* 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
|
||||
@@ -262,3 +270,75 @@
|
||||
write_wtmp(user, id, pid, type, line && line[0] ? line : oldline);
|
||||
}
|
||||
|
||||
+#if defined(USE_PAM) && defined(INIT_MAIN)
|
||||
+static pam_handle_t *pamh = NULL;
|
||||
+# ifdef __GNUC__
|
||||
+static int
|
||||
+null_conv(int num_msg, const struct pam_message **msgm,
|
||||
+ struct pam_response **response __attribute__((unused)),
|
||||
+ void *appdata_ptr __attribute__((unused)))
|
||||
+# else
|
||||
+static int
|
||||
+null_conv(int num_msg, const struct pam_message **msgm,
|
||||
+ struct pam_response **response, void *appdata_ptr)
|
||||
+# endif
|
||||
+{
|
||||
+ int i;
|
||||
+ for (i = 0; i < num_msg; i++) {
|
||||
+ const struct pam_message *msg = msgm[i];
|
||||
+ if (msg == (const struct pam_message*)0)
|
||||
+ continue;
|
||||
+ if (msg->msg == (char*)0)
|
||||
+ continue;
|
||||
+ switch (msg->msg_style) {
|
||||
+ case PAM_ERROR_MSG:
|
||||
+ case PAM_TEXT_INFO:
|
||||
+ initlog(L_VB, "pam_message %s", msg->msg);
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+static const struct pam_conv conv = { null_conv, NULL };
|
||||
+# define PAM_FAIL_CHECK(func, args...) \
|
||||
+ { \
|
||||
+ if ((pam_ret = (func)(args)) != PAM_SUCCESS) { \
|
||||
+ initlog(L_VB, "%s", pam_strerror(pamh, pam_ret)); \
|
||||
+ goto pam_error; \
|
||||
+ } \
|
||||
+ }
|
||||
+
|
||||
+void notify_pam_dead_session(const char *id)
|
||||
+{
|
||||
+ struct utmp *oldut, ut;
|
||||
+
|
||||
+ setutent();
|
||||
+
|
||||
+ memset(&ut, 0, sizeof(ut));
|
||||
+ ut.ut_type = DEAD_PROCESS;
|
||||
+ strncpy(ut.ut_id, id, sizeof(ut.ut_id));
|
||||
+
|
||||
+ if ((oldut = getutid(&ut)) && (oldut->ut_type == USER_PROCESS)) {
|
||||
+ int pam_ret;
|
||||
+ char tty[UT_LINESIZE+ strlen(_PATH_DEV) + 1];
|
||||
+
|
||||
+ if (strncmp(oldut->ut_line, _PATH_DEV, strlen(_PATH_DEV)))
|
||||
+ snprintf(tty, sizeof(tty), _PATH_DEV "%.*s",
|
||||
+ UT_LINESIZE, oldut->ut_line);
|
||||
+ else
|
||||
+ snprintf(tty, sizeof(tty), "%.*s",
|
||||
+ UT_LINESIZE, oldut->ut_line);
|
||||
+
|
||||
+ PAM_FAIL_CHECK(pam_start, "init", oldut->ut_user, &conv, &pamh);
|
||||
+ PAM_FAIL_CHECK(pam_set_item, pamh, PAM_TTY, tty);
|
||||
+ PAM_FAIL_CHECK(pam_set_item, pamh, PAM_RHOST, oldut->ut_host);
|
||||
+ PAM_FAIL_CHECK(pam_close_session, pamh, PAM_SILENT);
|
||||
+ pam_error:
|
||||
+ pam_end(pamh, pam_ret);
|
||||
+ }
|
||||
+
|
||||
+ endutent();
|
||||
+}
|
||||
+#endif /* USE_PAM && INIT_MAIN */
|
||||
+
|
||||
Index: src/Makefile
|
||||
===================================================================
|
||||
--- src/Makefile (revision 58)
|
||||
+++ src/Makefile (working copy)
|
||||
@@ -8,7 +8,7 @@
|
||||
# Version: @(#)Makefile 2.85-13 23-Mar-2004 miquels@cistron.nl
|
||||
#
|
||||
|
||||
-CPPFLAGS =
|
||||
+CPPFLAGS = -DUSE_PAM
|
||||
CFLAGS ?= -ansi -O2 -fomit-frame-pointer
|
||||
override CFLAGS += -W -Wall -D_GNU_SOURCE
|
||||
STATIC =
|
||||
@@ -79,6 +79,13 @@
|
||||
endif
|
||||
|
||||
# Additional libs for GNU libc.
|
||||
+ifneq ($(findstring -DUSE_PAM,$(CPPFLAGS)),)
|
||||
+ INITLIBS += -lpam
|
||||
+ PAMDOTD = /etc/pam.d
|
||||
+ PAMINIT = $(PAMDOTD)/init
|
||||
+endif
|
||||
+
|
||||
+# Additional libs for GNU libc.
|
||||
ifneq ($(wildcard /usr/lib*/libcrypt.a),)
|
||||
SULOGINLIBS += -lcrypt
|
||||
endif
|
||||
@@ -153,6 +160,11 @@
|
||||
$(STRIP) $$i ; \
|
||||
$(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
|
||||
done
|
||||
+ifneq ($(findstring -DUSE_PAM,$(CPPFLAGS)),)
|
||||
+ $(INSTALL_DIR) $(ROOT)$(PAMDOTD)
|
||||
+ test -s $(ROOT)$(PAMINIT) || \
|
||||
+ $(INSTALL_DATA) init.sample $(ROOT)$(PAMINIT)
|
||||
+endif
|
||||
# $(INSTALL_DIR) $(ROOT)/etc/
|
||||
# $(INSTALL_EXEC) initscript.sample $(ROOT)/etc/
|
||||
ln -sf halt $(ROOT)/sbin/reboot
|
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,73 @@
|
|||
|
||||
Install instructions for the System V style init
|
||||
|
||||
init, shutdown, halt, reboot, wall, last, mesg, runlevel,
|
||||
killall5, pidof, sulogin.
|
||||
|
||||
All programs, files and scripts in this package are covered by
|
||||
the GNU General Public License version 2, and copyrighted by
|
||||
Miquel van Smoorenburg (1991-2004) and, Jesse Smith (2018).
|
||||
|
||||
If you are not using Debian and the debianized package,
|
||||
you may have to install the new init by hand if Debian is
|
||||
using an init system other than SysV (eg systemd). You should
|
||||
be able to drop the binaries into a Slackware or Devuan system, I think.
|
||||
|
||||
The SysV init software, core programs and manual pages can be
|
||||
installed by running the following two commands from the top-level
|
||||
source directory.
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
||||
If sudo is not installed, the "make install" command may be run as
|
||||
the root user.
|
||||
|
||||
Other than the GNU make utility, SysV init has few dependencies.
|
||||
SysV can be built on virtually any Linux system featuring
|
||||
the GNU C library or musl libc. A C compiler, such as the GNU Compiler
|
||||
Collection (GCC) or Clang is also required.
|
||||
|
||||
Here is a list of preferred directories to install the progs & manpages,
|
||||
this should be done for you automatically when you run "make install"
|
||||
as the root user, or via sudo, ie "sudo make install".
|
||||
|
||||
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 version of 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?):
|
||||
* All communication to init goes through the FIFO /run/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.
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
|
||||
Propaganda for version 2.89 of sysvinit & utilities
|
||||
==================================================
|
||||
|
||||
NOTE: If you use a standard distribution like Slackware, Devuan
|
||||
or Gentoo 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.
|
||||
|
||||
SysV init was probably the most widely used init package for Linux.
|
||||
Most distributions once used it. sysvinit 2.4 was really a good package,
|
||||
and it was not the need for bug fixes but the need for more features
|
||||
that made me work on sysvinit again.
|
||||
|
||||
SysV init 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:
|
||||
|
||||
http://download.savannah.nongnu.org/releases/sysvinit/
|
||||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
This document describes the communiction pipe set up by SysV init
|
||||
at /run/initctl. This named pipe allows programs with the proper
|
||||
permissions (typically programs run by root have read+write access to
|
||||
the pipe) to send signals to the init program (PID 1).
|
||||
|
||||
The init manual page has, up until recently, simply stated
|
||||
that people wishing to understand how to send messages to init
|
||||
should read the init program's source code, but that is not usually practical.
|
||||
|
||||
Messages sent to the pipe to talk to init must have a special format.
|
||||
This format is defined as a C structure and the technical break-down
|
||||
is presented here:
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
||||
Let's go through the init_request structure one line at a time. The
|
||||
first variable, the "magic" number must be of the value 0x03091969.
|
||||
The init program then knows that only programs with root access which send
|
||||
this magic number are authorized to communicate with init.
|
||||
|
||||
The cmd variable is a value in the range of 0-8 (currently). This cmd
|
||||
variable tells init what we want it to do. Here are the possible options:
|
||||
|
||||
1 - Set the current runlevel, specified by the runlevel variable.
|
||||
2 - The power will fail soon (probably low battery) prepare to shutdown.
|
||||
3 - The power is failing, do shutdown immediately.
|
||||
4 - The power is okay, cancel shutdown.
|
||||
6 - Set an environment variable to a value to be specified in
|
||||
the data variable of this structure.
|
||||
|
||||
Other cmd options may be added to init later. For example, command values
|
||||
0, 5 and 7 are defined but currently not implemented.
|
||||
|
||||
The runlevel variable will specify the runlevel to switch to (0-6).
|
||||
|
||||
The sleeptime variable is to be used when we want to tell init to change
|
||||
the time spent waiting between sending SIGTERM and SIGKILL during the
|
||||
shutdown process. Changing this at run time is not yet implemented.
|
||||
|
||||
The data variable (in the union) can be used to pass misc data which init
|
||||
might need to process our request. For example, when setting environment
|
||||
variables.
|
||||
|
||||
When setting an environment variable through init's /run/initctl pipe,
|
||||
the data variable should have the format VARIABLE=VALUE. The string
|
||||
should be terminated with a NULL '\0' character.
|
||||
|
||||
|
||||
The following C code example shows how to send a set environment variable
|
||||
request to the init process using the /run/initctl pipe. This example
|
||||
is simplified and skips the error checking. A more comlpete example can be
|
||||
found in the shutdown.c program's init_setnv() function.
|
||||
|
||||
|
||||
struct init_request request; /* this is the structure defined above */
|
||||
int fd; /* file descriptor for the pipe */
|
||||
|
||||
memset(&request, 0, sizeof(request)); /* initialize structure */
|
||||
request.magic = 0x03091969; /* this magic number must be included */
|
||||
request.cmd = 6; /* 6 is the command to set a variable */
|
||||
sprintf(request.data, "VARIABLE=VALUE"); /* set VARIABLE to VALUE in init */
|
||||
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) /* open pipe for writing */
|
||||
{
|
||||
size_t s = sizeof(request); /* size of the structure to write */
|
||||
void *ptr = &request; /* temporary pointer */
|
||||
write(fd, ptr, s); /* send the structure to the pipe */
|
||||
close(fd); /* close the pipe when done */
|
||||
}
|
||||
|
||||
|
||||
|
||||
Usually the /run/initctl pipe would only be used by low-level programs to
|
||||
request a power-related shutdown or change the runlevel, like telinit
|
||||
would do. Most of the time there is no need to talk to init directly, but
|
||||
this gives us an extenable approach so init can be taught how to learn
|
||||
more commands.
|
||||
|
|
@ -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"
|
|
@ -0,0 +1,82 @@
|
|||
'\" -*- 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 [ \-e ]
|
||||
.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\-e\fP
|
||||
Print escape characters to the boot log file. This turns off filtering of
|
||||
escape characters and allows tools like GNU Less to see and use colour control
|
||||
characters (show the log in colour).
|
||||
.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 NOTES
|
||||
bootlogd saves log data which includes control characters. The log is
|
||||
technically a text file, but not very easy for humans to read. To address
|
||||
this the readbootlog(1) command can be used to display the boot log
|
||||
without the control characters.
|
||||
.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), readbootlog(1).
|
|
@ -0,0 +1,71 @@
|
|||
'\" -*- coding: UTF-8 -*-
|
||||
.\" A man page for fstab-decode(8).
|
||||
.\"
|
||||
.\" Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
||||
.\"
|
||||
.\" This copyrighted material is made available to anyone wishing to use,
|
||||
.\" modify, copy, or redistribute it subject to the terms and conditions of the
|
||||
.\" GNU General Public License v.2.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" Author: Miloslav Trmac <mitr@redhat.com>
|
||||
.TH fstab-decode 8 "May 2006"
|
||||
|
||||
.SH NAME
|
||||
fstab-decode \- run a command with fstab-encoded arguments
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBfstab-decode\fR \fICOMMAND\fR [\fIARGUMENT\fR]...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B fstab-decode
|
||||
decodes escapes (such as newline characters and other whitespace)
|
||||
in the specified \fIARGUMENT\fRs and uses them to run \fICOMMAND\fR.
|
||||
The argument escaping uses the same rules as path escaping in
|
||||
\fB/etc/fstab\fR,
|
||||
.B /etc/mtab
|
||||
and \fB/proc/mtab\fR.
|
||||
|
||||
In essence fstab-decode can be used anytime we want to pass multiple
|
||||
parameters to a command as a list of command line argments. It turns output
|
||||
like this:
|
||||
|
||||
.nf
|
||||
/root
|
||||
/mnt/remote-disk
|
||||
/home
|
||||
|
||||
Into one long list of parameters, "/root /mnt/remote-disk /home". This
|
||||
can be useful when trying to work with multiple filesystems at once. For
|
||||
instance, we can use it to unmount multiple NFS shares. This program also
|
||||
removes whitespace and other characters which might cause programs such
|
||||
as mount or umount to fail.
|
||||
|
||||
.SH EXIT STATUS
|
||||
.B fstab-decode
|
||||
exits with status 127 if
|
||||
.I COMMAND
|
||||
can't be run.
|
||||
Otherwise it exits with the status returned by \fICOMMAND\fR.
|
||||
|
||||
.SH EXAMPLES
|
||||
.nf
|
||||
The following example reads fstab, finds all instances of VFAT filesystems and
|
||||
prints their mount points (argument 2 in the fstab file). fstab-decode then runs
|
||||
the specified program, umount, and passes it the list of VFAT mountpoints.
|
||||
This unmounts all VFAT partitions.
|
||||
|
||||
|
||||
.B fstab-decode umount $(awk \[aq]$3 == \[dq]vfat\[dq] { print $2 }\[aq] /etc/fstab)
|
||||
.fi
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR fstab (5)
|
|
@ -0,0 +1,123 @@
|
|||
'\" -*- 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. This implies \fB\-d\fP.
|
||||
.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.
|
||||
.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.
|
||||
Warning: This may not work on interfaces which do not have an IP address
|
||||
and should ideally be handled by a network manager service.
|
||||
.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 and /var/run/runlevel does not exist) \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)
|
||||
.\"}}}
|
|
@ -0,0 +1,353 @@
|
|||
'\" -*- 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/init
|
||||
.RB [ " --version " ]
|
||||
.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 (a.k.a. \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 \fBS\fP, \fB0\fP, \fB1\fP, and \fB6\fP are reserved.
|
||||
Runlevel S is used to initialize the system on boot.
|
||||
When starting runlevel S (on boot)
|
||||
or runlevel 1 (switching from a multi-user runlevel)
|
||||
the system is entering ``single-user mode'', after which the
|
||||
current runlevel is S.
|
||||
Runlevel 0 is used to halt the system;
|
||||
runlevel 6 is used to reboot the system.
|
||||
.PP
|
||||
After booting through S the system automatically enters one of
|
||||
the multi-user runlevels 2 through 5, unless there was some
|
||||
problem that needs to be fixed by the administrator in
|
||||
single-user mode.
|
||||
Normally after entering single-user mode
|
||||
the administrator performs maintenance and then reboots the system.
|
||||
.PP
|
||||
For more information,
|
||||
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.
|
||||
.PP
|
||||
Runlevels \fIS\fP and \fIs\fP are 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 initialize the system
|
||||
and do not require an \fB/etc/inittab\fP file.
|
||||
.PP
|
||||
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 (reload) 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/run/initctl\fP
|
||||
control channel - see the initctl manual page 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 3 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. Runlevel 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 3 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 or GRUB). \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
|
||||
.TP 0.5i
|
||||
.B \-\-version
|
||||
This argument, when used on its own, displays the current version of init
|
||||
to the console/stdout. It is a quick way to determine which init software and
|
||||
version is being used. After the version information is displayed, init
|
||||
immediately exits with a return code of zero.
|
||||
.PP
|
||||
.SH INTERFACE
|
||||
Init listens on a \fIfifo\fP in /dev, \fI/run/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/run/initctl\fP. Useful for bootscripts when /dev is remounted.
|
||||
.TP 0.5i
|
||||
.B SIGUSR2
|
||||
When init receives SIGUSR2, init closes and leaves the control fifo,
|
||||
\fB/run/initctl\fP, closed. This may be used to make sure init is not
|
||||
holding open any files. However, it also prevents init from switching
|
||||
runlevels. Which means commands like shutdown no longer work.
|
||||
The fifo can be re-opened by sending init the SIGUSR1 signal.
|
||||
.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
|
||||
/run/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.
|
||||
.PP
|
||||
On a Debian system, entering runlevel 1 causes all processes
|
||||
to be killed except for kernel threads and the script that does
|
||||
the killing and other processes in its session.
|
||||
As a consequence of this, it isn't safe to return from runlevel 1
|
||||
to a multi-user runlevel: daemons that were started in runlevel S
|
||||
and are needed for normal operation are no longer running.
|
||||
The system should be rebooted.
|
||||
.\"}}}
|
||||
.\"{{{ 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 initctl (5),
|
||||
.BR inittab (5),
|
||||
.BR initscript (5),
|
||||
.BR utmp (5)
|
||||
.\"}}}
|
|
@ -0,0 +1,148 @@
|
|||
'\" -*- coding: UTF-8 -*-
|
||||
.\" Copyright (C) 2018 Jesse Smith
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" 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 INITCTL 5 "April 13, 2018" "" "Linux System Administrator's Manual"
|
||||
.SH NAME
|
||||
initctl \- /run/initctl is a named pipe which passes commands to SysV init.
|
||||
.SH SYNOPSIS
|
||||
/run/initctl
|
||||
.SH DESCRIPTION
|
||||
|
||||
This document describes the communiction pipe set up by SysV init
|
||||
at /run/initctl. This named pipe allows programs with the proper
|
||||
permissions (typically programs run by root have read+write access to
|
||||
the pipe) to send signals to the init program (PID 1).
|
||||
|
||||
The init manual page has, up until recently, simply stated
|
||||
that people wishing to understand how to send messages to init
|
||||
should read the init program's source code, but that is not usually practical.
|
||||
|
||||
Messages sent to the pipe to talk to init must have a special format.
|
||||
This format is defined as a C structure and the technical break-down
|
||||
is presented here:
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
||||
Let's go through the init_request structure one line at a time. The
|
||||
first variable, the "magic" number must be of the value 0x03091969.
|
||||
The init program then knows that only programs with root access which send
|
||||
this magic number are authorized to communicate with init.
|
||||
|
||||
The cmd variable is a value in the range of 0-8 (currently). This cmd
|
||||
variable tells init what we want it to do. Here are the possible options:
|
||||
|
||||
1 - Set the current runlevel, specified by the runlevel variable.
|
||||
|
||||
2 - The power will fail soon (probably low battery) prepare to shutdown.
|
||||
|
||||
3 - The power is failing, do shutdown immediately.
|
||||
|
||||
4 - The power is okay, cancel shutdown.
|
||||
|
||||
6 - Set an environment variable to a value to be specified in
|
||||
the data variable of this structure.
|
||||
|
||||
Other cmd options may be added to init later. For example, command values
|
||||
0, 5 and 7 are defined but currently not implemented.
|
||||
|
||||
The runlevel variable will specify the runlevel to switch to (0-6).
|
||||
|
||||
The sleeptime variable is to be used when we want to tell init to change
|
||||
the time spent waiting between sending SIGTERM and SIGKILL during the
|
||||
shutdown process. Changing this at run time is not yet implemented.
|
||||
|
||||
The data variable (in the union) can be used to pass misc data which init
|
||||
might need to process our request. For example, when setting environment
|
||||
variables.
|
||||
|
||||
When setting an environment variable through init's /run/initctl pipe,
|
||||
the data variable should have the format VARIABLE=VALUE. The string
|
||||
should be terminated with a NULL character.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
The following C code example shows how to send a set environment variable
|
||||
request to the init process using the /run/initctl pipe. This example
|
||||
is simplified and skips the error checking. A more comlpete example can be
|
||||
found in the shutdown.c program's init_setnv() function.
|
||||
|
||||
.nf
|
||||
struct init_request request; /* structure defined above */
|
||||
int fd; /* file descriptor for pipe */
|
||||
|
||||
memset(&request, 0, sizeof(request)); /* initialize structure */
|
||||
request.magic = 0x03091969; /* magic number required */
|
||||
request.cmd = 6; /* 6 is to set a variable */
|
||||
sprintf(request.data, "VARIABLE=VALUE"); /* set VAR to VALUE in init */
|
||||
|
||||
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) /* open pipe for writing */
|
||||
{
|
||||
size_t s = sizeof(request); /* size of structure to write */
|
||||
void *ptr = &request; /* temporary pointer */
|
||||
write(fd, ptr, s); /* send structure to the pipe */
|
||||
close(fd); /* close the pipe when done */
|
||||
}
|
||||
.fi
|
||||
|
||||
.sp
|
||||
.SH NOTES
|
||||
Usually the /run/initctl pipe would only be used by low-level programs to
|
||||
request a power-related shutdown or change the runlevel, like telinit
|
||||
would do. Most of the time there is no need to talk to init directly, but
|
||||
this gives us an extenable approach so init can be taught how to learn
|
||||
more commands.
|
||||
.PP
|
||||
The commands passed through the /run/initctl pipe must be sent in a specific
|
||||
binary format and be of a specific length. Larger data structures or ones
|
||||
not using the proper format will be ignored. Typically, only root has the
|
||||
ability to write to the initctl pipe for security reasons.
|
||||
.PP
|
||||
The /run/initctl pipe can be closed by sending init (PID 1) the SIGUSR2
|
||||
signal. This closes the pipe and leaves it closed. This may be useful
|
||||
for making sure init is not keeping any files open. However, when the
|
||||
pipe is closed, init no longer receives signals, such as those sent by
|
||||
shutdown or telinit. In other words if we close the pipe, init cannot
|
||||
change its runlevel directly. The pipe may be re-opened by sending init (PID 1)
|
||||
the SIGUSR1 signal.
|
||||
.PP
|
||||
If the /run/initctl pipe is closed then it may still be possible to bring
|
||||
down the system using the shutdown command's -n flag, but this is not
|
||||
always clean and not recommended.
|
||||
.SH FILES
|
||||
/run/initctl
|
||||
/sbin/init
|
||||
.SH AUTHOR
|
||||
Jesse Smith <jsmith@resonatingmedia.com>
|
||||
.SH "SEE ALSO"
|
||||
init(8)
|
|
@ -0,0 +1,71 @@
|
|||
'\" -*- 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.
|
||||
.SH FILES
|
||||
/etc/inittab,
|
||||
/etc/initscript.
|
||||
.SH AUTHOR
|
||||
Miquel van Smoorenburg ,<miquels@cistron.nl>
|
||||
.SH "SEE ALSO"
|
||||
init(8), inittab(5).
|
|
@ -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. The length of this field is limited to 127 characters.
|
||||
.\"}}}
|
||||
.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)
|
||||
.\"}}}
|
|
@ -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
|
||||
.B \-signalnumber
|
||||
.RB [ \-o
|
||||
.IR omitpid [, omitpid ...]]
|
||||
.RB [ \-o
|
||||
.IR omitpid [, 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
|
|
@ -0,0 +1,128 @@
|
|||
'\" -*- 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 ]
|
||||
[\-\fBn\fP \fInum\/\fP]
|
||||
.RB [ \-adFiowx ]
|
||||
[\-\fBf\fP \fIfile\/\fP]
|
||||
[\-\fBt\fP \fIYYYYMMDDHHMMSS\/\fP]
|
||||
.RI [ name... ]
|
||||
.RI [ tty... ]
|
||||
.br
|
||||
.B lastb
|
||||
.RB [ \-R ]
|
||||
.RB [ \-\fInum\fP ]
|
||||
[\-\fBn\fP \fInum\/\fP]
|
||||
[\-\fBf\fP \fIfile\/\fP]
|
||||
.RB [ \-adFiowx ]
|
||||
.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\-l\fP
|
||||
This option allows the display of usernames longer than 8 characters.
|
||||
This may mess up formatting in some programs and make the output wider than
|
||||
the standard 80 characters.
|
||||
.IP \fB\-o\fP
|
||||
Read an old-type wtmp file (written by linux-libc5 applications).
|
||||
.IP \fB\-w\fP
|
||||
Display full user and domain names in the output.
|
||||
.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)
|
||||
.\"}}}
|
|
@ -0,0 +1 @@
|
|||
.so man1/last.1
|
|
@ -0,0 +1,61 @@
|
|||
.\" -*- nroff -*-
|
||||
.\" Copyright 2003 by Theodore Ts'o. All Rights Reserved.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH LOGSAVE 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
|
||||
.SH NAME
|
||||
logsave \- save the output of a command in a logfile
|
||||
.SH SYNOPSIS
|
||||
.B logsave
|
||||
[
|
||||
.B \-asv
|
||||
]
|
||||
.I logfile cmd_prog [ ... ]
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B logsave
|
||||
program will execute
|
||||
.I cmd_prog
|
||||
with the specified argument(s), and save a copy of its output to
|
||||
.IR logfile .
|
||||
If the containing directory for
|
||||
.I logfile
|
||||
does not exist,
|
||||
.B logsave
|
||||
will accumulate the output in memory until it can be written out.
|
||||
A copy of the output will also be written to standard output.
|
||||
.PP
|
||||
If
|
||||
.I cmd_prog
|
||||
is a single hyphen ('-'), then instead of executing a program,
|
||||
.B logsave
|
||||
will take its input from standard input and save it in
|
||||
.I logfile
|
||||
.PP
|
||||
.B logsave
|
||||
is useful for saving the output of initial boot scripts
|
||||
until the /var partition is mounted, so the output can be written to
|
||||
/var/log.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-a
|
||||
This option will cause the output to be appended to
|
||||
.IR logfile ,
|
||||
instead of replacing its current contents.
|
||||
.TP
|
||||
.B \-s
|
||||
This option will cause
|
||||
.B logsave
|
||||
to skip writing to the log file text which is bracketed with a control-A
|
||||
(ASCII 001 or Start of Header) and control-B (ASCII 002 or Start of
|
||||
Text). This allows progress bar information to be visible to the user
|
||||
on the console, while not being written to the log file.
|
||||
.TP
|
||||
.B \-v
|
||||
This option will make
|
||||
.B logsave
|
||||
to be more verbose in its output to the user.
|
||||
.SH AUTHOR
|
||||
Theodore Ts'o (tytso@mit.edu)
|
||||
.SH SEE ALSO
|
||||
.BR fsck (8)
|
|
@ -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)
|
||||
.\"}}}
|
|
@ -0,0 +1,69 @@
|
|||
'\" -*- 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
|
||||
.B \-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\-p\fP
|
||||
Check Linux's /proc/mounts file to try to detect circular mount points.
|
||||
.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
|
||||
The mountpoint command fails when a directory is binded to one of its grandparents.
|
||||
For example, if /a/b/c/d is a mount point for /a/b then mountpoint will report
|
||||
/a/b/c/d is not a valid mount point. This is because both the original directory and
|
||||
its new mount point share the same inode and device number.
|
||||
.PP
|
||||
The circular mount problem can be worked around on Linux systems by using
|
||||
the -p flag to check the /proc/mounts file for references to the circular mount bind.
|
||||
When using the -p flag, make sure to specify the full path (ie /home/user/mp and
|
||||
not just mp). Also, mountpoint may still fail if there are spaces in
|
||||
the mount point's path, even when using the -p flag because of the way
|
||||
/proc/mounts mangles the spaces in the path name. Of course, if the
|
||||
admin is using circular mount points with spaces in the name, there
|
||||
are bigger concerns.
|
||||
.SH AUTHOR
|
||||
Miquel van Smoorenburg, miquels@cistron.nl
|
||||
.SH "SEE ALSO"
|
||||
.BR stat (1)
|
|
@ -0,0 +1,110 @@
|
|||
'\" -*- 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 [ \-n ]
|
||||
.RB [ \-x ]
|
||||
.RB [ \-z ]
|
||||
.RB [ \-o
|
||||
.IR omitpid[,omitpid...] ]
|
||||
.RB [ \-o
|
||||
.IR omitpid[,omitpid...]... ]
|
||||
.RB [ \-d
|
||||
.IR sep ]
|
||||
.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 PIDs 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 \-n
|
||||
Avoid
|
||||
.BR stat (2)
|
||||
system function call on all binaries which are located on network
|
||||
based file systems like
|
||||
.BR NFS .
|
||||
Instead of using this option the variable
|
||||
.B PIDOF_NETFS
|
||||
may be set and exported.
|
||||
.IP \-q
|
||||
Do not display matched PIDs to standard out. Simply exit with
|
||||
a status of true or false to indicate whether a matching PID was found.
|
||||
.IP \-x
|
||||
Scripts too - this causes the program to also return process id's of
|
||||
shells running the named scripts.
|
||||
.IP \-z
|
||||
Try to detect processes which are stuck in uninterruptible (D) or zombie (Z)
|
||||
status. Usually these processes are skipped as trying to deal with them can cause
|
||||
pidof to hang.
|
||||
.IP "-d \fIsep\fP"
|
||||
Tells \fIpidof\fP to use \fIsep\fP as an output separator if more than one PID
|
||||
is shown. The default separator is a space.
|
||||
.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. Note
|
||||
that the executable name of running processes is calculated with
|
||||
.BR readlink (2),
|
||||
so symbolic links to executables will also match.
|
||||
.PP
|
||||
Zombie processes or processes in disk sleep (states Z and D, respectively)
|
||||
are ignored, as attempts to access the stats of these will sometimes fail.
|
||||
The \-z flag (see above) tells pidof to try to detect these sleeping and zombie
|
||||
processes, at the risk of failing or hanging.
|
||||
|
||||
.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
|
|
@ -0,0 +1 @@
|
|||
.so man8/halt.8
|
|
@ -0,0 +1,58 @@
|
|||
'\" -*- 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 READBOOTLOG 1 "NOV 12, 2018" "" "Linux System Administrator's Manual"
|
||||
.\"}}}
|
||||
.\"{{{ Name
|
||||
.SH NAME
|
||||
readbootlog \- show contents of the boot log, stripping away control characters
|
||||
.\"}}}
|
||||
.\"{{{ Synopsis
|
||||
.SH SYNOPSIS
|
||||
.B readbootlog
|
||||
.RB [ \-h ]
|
||||
[\-\fBf\fP \fIfile\/\fP]
|
||||
.br
|
||||
.\"}}}
|
||||
.\"{{{ Description
|
||||
.SH DESCRIPTION
|
||||
.B readbootlog
|
||||
is a tool for reading the boot log (by default /var/log/boot). The program
|
||||
strips away control characters and non-human readable contents from the log
|
||||
file. Output is dumped to the terminal where it can be piped or redirected
|
||||
to a file.
|
||||
.\"}}}
|
||||
.\"{{{ Options
|
||||
.SH OPTIONS
|
||||
.IP "\fB\-f\fP \fIfile\fP"
|
||||
Tells \fBreadbootlog\fP to use a specific file instead of \fB/var/log/boot\fP.
|
||||
.IP \fB\-h\fP
|
||||
Displays a brief help message.
|
||||
.\"{{{ Files
|
||||
.SH FILES
|
||||
/var/log/boot
|
||||
.\"}}}
|
||||
.\"{{{ Author
|
||||
.SH AUTHOR
|
||||
Jesse Smith <jsmith@resonatingmedia.com>
|
||||
.\"}}}
|
||||
.\"{{{ See also
|
||||
.SH "SEE ALSO"
|
||||
.BR bootlogd (8)
|
||||
.\"}}}
|
|
@ -0,0 +1 @@
|
|||
.so man8/halt.8
|
|
@ -0,0 +1,58 @@
|
|||
'\" -*- 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, and if no runlevel record can be found in the
|
||||
.I /var/run/runlevel
|
||||
file,
|
||||
.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
|
|
@ -0,0 +1,240 @@
|
|||
'\" -*- 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 [ \-akrhPHfFnc ]
|
||||
.RB [ \-t
|
||||
.IR sec ]
|
||||
.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.
|
||||
.\"}}}
|
||||
.\"{{{ -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. Usually used with the -P or -H flags,
|
||||
depending on whether we want to poweroff or simply stop the operating system.
|
||||
.\"}}}
|
||||
.\"{{{ -P
|
||||
.IP \fB\-P\fP
|
||||
Modifier to the -h flag. Halt action is to turn off the power.
|
||||
Must be used with the -h flag.
|
||||
.\"}}}
|
||||
.\"{{{ -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.
|
||||
Halting is often used to run through the shutdown process and leave
|
||||
output on the screen for debugging purposes. Or when the user wants the OS to
|
||||
stop, but leave the power on. To power off at the end of the shutdown sequence
|
||||
use the -P modifier instead.
|
||||
.\"}}}
|
||||
.\"{{{ -f
|
||||
.IP \fB\-f\fP
|
||||
Skip fsck on reboot.
|
||||
.\"}}}
|
||||
.\"{{{ -F
|
||||
.IP \fB\-F\fP
|
||||
Force fsck on reboot.
|
||||
.\"}}}
|
||||
.\"{{{ -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.
|
||||
.\"}}}
|
||||
.\"{{{ -c
|
||||
.IP \fB\-c\fP
|
||||
Cancel a waiting shutdown. ("shutdown now" is no longer waiting.) With
|
||||
this option it is of course not possible to give the time argument, but
|
||||
you can enter explanatory message arguments on the command line that
|
||||
will be sent to all users.
|
||||
.\"{{{ -q
|
||||
.IP \fB\-q
|
||||
Reduce the number of warnings shutdown displays. Usually shutdown displays
|
||||
warnings every 15 minutes and then every minute in the last 10 minutes of the
|
||||
countdown until \fItime\fP is reached. When \-q is specified
|
||||
shutdown only warns at 60 minute intervals, at the 10 minute mark,
|
||||
at the 5 minue mark, and when the shutdown process actually happens.
|
||||
.\"{{{ -Q
|
||||
.IP \fB\-Q
|
||||
Silence warnings prior to shutting down. Usually shutdown displays
|
||||
warnings every 15 minutes and then every minute in the last 10 minutes of the
|
||||
countdown until \fItime\fP is reached. When \-Q is specified
|
||||
shutdown only warns when the shutdown process actually happens. All
|
||||
other warning intervals are suppressed.
|
||||
.\"}}}
|
||||
.\"{{{ -t sec
|
||||
.IP "\fB\-t\fP \fIsec\fP"
|
||||
Tell \fBinit\fP(8) to wait \fIsec\fP seconds between sending all processes the
|
||||
warning (SIGTERM) and the kill signal (SIGKILL), before changing to another runlevel.
|
||||
The default time, if no value is specified, between these two signals is
|
||||
three seconds. Warning: when shutdown calls init to perform the shutdown (the
|
||||
default behaviour), init checks to see if all processes have terminated
|
||||
and will stop waiting early once its children have all terminated.
|
||||
When shutdown is called with the -n flag, it waits the full time specified
|
||||
(or three seconds) even if all other processes have terminated.
|
||||
.\"}}}
|
||||
.\"{{{ 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 script (usually /etc/init.d/halt) that calls
|
||||
the \fBhalt\fP(8) program as the last thing in the shutting down sequence should
|
||||
check this environment variable and call the \fBhalt\fP(8) program with
|
||||
the right options for these options to actually have any effect.
|
||||
.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)
|
||||
.\"}}}
|
|
@ -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).
|
|
@ -0,0 +1 @@
|
|||
.so man8/init.8
|
|
@ -0,0 +1,66 @@
|
|||
'\" -*- coding: UTF-8 -*-
|
||||
.\" Copyright (C) 2010 Michael Krapp
|
||||
.\"
|
||||
.\" 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 UTMPDUMP 1 "Februar 8, 2010" "" "Linux System Administrator's Manual"
|
||||
.SH NAME
|
||||
utmpdump \- dump UTMP and WTMP files in raw format
|
||||
.SH SYNOPSIS
|
||||
.B utmpdump
|
||||
.RB [ \-froh ]
|
||||
.I filename
|
||||
.SH DESCRIPTION
|
||||
\fButmpdump\fP is a simple program to dump UTMP and WTMP files
|
||||
in raw format, so they can be examined.
|
||||
.SH OPTIONS
|
||||
.IP \fB\-f\fP
|
||||
output appended data as the file grows.
|
||||
.IP "\fB\-r\fP"
|
||||
reverse. Write back edited login information into utmp or wtmp files.
|
||||
.IP \fB\-o\fP
|
||||
use old libc5 format.
|
||||
.IP \fB\-h\fP
|
||||
usage information.
|
||||
.PP
|
||||
utmpdump can be useful in cases of corrupted utmp or wtmp entries.
|
||||
It can dump out utmp/wtmp to an ASCII file, then that file can
|
||||
be edited to remove bogus entries and reintegrated, using
|
||||
.PP
|
||||
.sp 1
|
||||
.in +1c
|
||||
.nf
|
||||
\fButmpdump -r < ascii file > wtmp\fP
|
||||
.fi
|
||||
.in -1c
|
||||
.sp 1
|
||||
but be warned as
|
||||
.B utmpdump
|
||||
was written for debugging purpose only.
|
||||
.SH BUGS
|
||||
You may
|
||||
.B not
|
||||
use the option \fB\-r\fP as the format for the
|
||||
utmp/wtmp files strongly depends on the
|
||||
input format. This tool was
|
||||
.B not
|
||||
written for normal use but for debugging.
|
||||
.SH AUTHOR
|
||||
Michael Krapp
|
||||
.SH "SEE ALSO"
|
||||
.BR last (1),
|
||||
.BR w (1),
|
||||
.BR who (1),
|
||||
.BR utmp (5),
|
|
@ -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\fP
|
||||
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
|
|
@ -0,0 +1,12 @@
|
|||
bootlogd
|
||||
fstab-decode
|
||||
halt
|
||||
init
|
||||
killall5
|
||||
last
|
||||
mesg
|
||||
runlevel
|
||||
shutdown
|
||||
sulogin
|
||||
utmpdump
|
||||
wall
|
|
@ -0,0 +1,237 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
CPPFLAGS =
|
||||
CFLAGS ?= -O2
|
||||
override CFLAGS += -ansi -fomit-frame-pointer -fstack-protector-strong -W -Wall -Wunreachable-code -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -D_XOPEN_SOURCE -D_GNU_SOURCE -DVERSION=\"$(VERSION)\"
|
||||
override CFLAGS += $(shell getconf LFS_CFLAGS)
|
||||
STATIC =
|
||||
MANDB := s@^\('\\\\\"\)[^\*-]*-\*- coding: [^[:blank:]]\+ -\*-@\1@
|
||||
|
||||
#
|
||||
# Leave empty if the mountpoint(1) command from util-linux 2.20
|
||||
# and above should be used, otherwise set it to yes.
|
||||
#
|
||||
MNTPOINT=
|
||||
|
||||
# For some known distributions we do not build all programs, otherwise we do.
|
||||
BIN =
|
||||
SBIN = init halt shutdown runlevel killall5 fstab-decode logsave
|
||||
USRBIN = last mesg readbootlog
|
||||
|
||||
MAN1 = last.1 lastb.1 mesg.1 readbootlog.1
|
||||
MAN5 = initscript.5 inittab.5 initctl.5
|
||||
MAN8 = halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8
|
||||
MAN8 += shutdown.8 telinit.8 fstab-decode.8 logsave.8
|
||||
|
||||
ifeq ($(DISTRO),)
|
||||
SBIN += sulogin bootlogd
|
||||
USRBIN += utmpdump wall
|
||||
MAN1 += utmpdump.1 wall.1
|
||||
MAN8 += sulogin.8 bootlogd.8
|
||||
endif
|
||||
|
||||
ifeq ($(DISTRO),Debian)
|
||||
CPPFLAGS+= -DACCTON_OFF
|
||||
SBIN += sulogin bootlogd
|
||||
MAN8 += sulogin.8 bootlogd.8
|
||||
MANDB :=
|
||||
endif
|
||||
|
||||
ifeq ($(DISTRO),Owl)
|
||||
USRBIN += wall
|
||||
MAN1 += wall.1
|
||||
MANDB :=
|
||||
endif
|
||||
|
||||
ifeq ($(DISTRO),SuSE)
|
||||
CPPFLAGS+= -DUSE_SYSFS -DSANE_TIO -DSIGINT_ONLYONCE -DUSE_ONELINE
|
||||
SBIN += sulogin
|
||||
USRBIN += utmpdump
|
||||
MAN1 += utmpdump.1
|
||||
MAN8 += sulogin.8
|
||||
MANDB :=
|
||||
endif
|
||||
|
||||
ifeq ($(MNTPOINT),yes)
|
||||
BIN += mountpoint
|
||||
MAN1 += mountpoint.1
|
||||
endif
|
||||
|
||||
ID = $(shell id -u)
|
||||
BIN_OWNER = root
|
||||
BIN_GROUP = root
|
||||
BIN_COMBO = $(BIN_OWNER):$(BIN_GROUP)
|
||||
ifeq ($(ID),0)
|
||||
INSTALL_EXEC = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 755
|
||||
INSTALL_DATA = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 644
|
||||
else
|
||||
INSTALL_EXEC = install -m 755
|
||||
INSTALL_DATA = install -m 644
|
||||
endif
|
||||
INSTALL_DIR = install -m 755 -d
|
||||
MANDIR = /usr/share/man
|
||||
|
||||
ifeq ($(WITH_SELINUX),yes)
|
||||
SELINUX_DEF = -DWITH_SELINUX
|
||||
INITLIBS += -lselinux
|
||||
SULOGINLIBS = -lselinux
|
||||
else
|
||||
SELINUX_DEF =
|
||||
INITLIBS =
|
||||
SULOGINLIBS =
|
||||
endif
|
||||
|
||||
# Additional libs for GNU libc.
|
||||
ifneq ($(wildcard /usr/lib*/libcrypt.*),)
|
||||
SULOGINLIBS += -lcrypt
|
||||
endif
|
||||
|
||||
# Additional libs for GNU libc / multiarch on Debian based systems.
|
||||
ifneq ($(wildcard /usr/lib/*/libcrypt.*),)
|
||||
SULOGINLIBS += -lcrypt
|
||||
endif
|
||||
|
||||
all: $(BIN) $(SBIN) $(USRBIN)
|
||||
|
||||
#%: %.o
|
||||
# $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
#%.o: %.c
|
||||
# $(CC) $(CFLAGS) $(CPPFLAGS) -c $^ -o $@
|
||||
|
||||
init: LDLIBS += $(INITLIBS) $(STATIC)
|
||||
init: init.o init_utmp.o runlevellog.o
|
||||
|
||||
halt: LDLIBS += $(STATIC)
|
||||
halt: halt.o ifdown.o hddown.o utmp.o runlevellog.o
|
||||
|
||||
last: LDLIBS += $(STATIC)
|
||||
last: last.o
|
||||
|
||||
logsave: LDLIBS += $(STATIC)
|
||||
logsave: logsave.o
|
||||
|
||||
mesg: LDLIBS += $(STATIC)
|
||||
mesg: mesg.o
|
||||
|
||||
mountpoint: LDLIBS += $(STATIC)
|
||||
mountpoint: mountpoint.o
|
||||
|
||||
utmpdump: LDLIBS += $(STATIC)
|
||||
utmpdump: utmpdump.o
|
||||
|
||||
runlevel: LDLIBS += $(STATIC)
|
||||
runlevel: runlevel.o runlevellog.o
|
||||
|
||||
sulogin: LDLIBS += $(SULOGINLIBS) $(STATIC)
|
||||
sulogin: sulogin.o consoles.o
|
||||
|
||||
wall: LDLIBS += $(STATIC)
|
||||
wall: dowall.o wall.o
|
||||
|
||||
shutdown: LDLIBS += $(STATIC)
|
||||
shutdown: dowall.o shutdown.o utmp.o
|
||||
|
||||
bootlogd: LDLIBS += -lutil $(STATIC)
|
||||
bootlogd: bootlogd.o
|
||||
|
||||
readbootlog: LDLIBS += $(STATIC)
|
||||
readbootlog: readbootlog.o
|
||||
|
||||
fstab-decode: LDLIBS += $(STATIC)
|
||||
fstab-decode: fstab-decode.o
|
||||
|
||||
sulogin.o: CPPFLAGS += $(SELINUX_DEF)
|
||||
sulogin.o: sulogin.c
|
||||
|
||||
runlevellog.o: runlevellog.h runlevellog.c paths.h
|
||||
|
||||
init.o: CPPFLAGS += $(SELINUX_DEF)
|
||||
init.o: init.c init.h initreq.h paths.h reboot.h runlevellog.h runlevellog.c set.h
|
||||
|
||||
utmp.o:
|
||||
|
||||
init_utmp.o: CPPFLAGS += -DINIT_MAIN
|
||||
init_utmp.o: utmp.c init.h initreq.h paths.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
bootlogd.o: bootlogd.c bootlogd.h
|
||||
|
||||
readbootlog.o: readbootlog.c
|
||||
|
||||
utmpdump.o: utmpdump.c oldutmp.h
|
||||
|
||||
shutdown.o: shutdown.c paths.h reboot.h initreq.h init.h
|
||||
|
||||
halt.o: halt.c reboot.h paths.h runlevellog.c runlevellog.h
|
||||
|
||||
last.o: last.c oldutmp.h
|
||||
|
||||
logsave.o: logsave.c
|
||||
|
||||
consoles.o: consoles.c consoles.h
|
||||
|
||||
cleanobjs:
|
||||
rm -f *.o *.bak
|
||||
|
||||
clean: cleanobjs clobber
|
||||
|
||||
clobber: cleanobjs
|
||||
rm -f $(BIN) $(SBIN) $(USRBIN)
|
||||
|
||||
distclean: clobber
|
||||
|
||||
install: all
|
||||
$(INSTALL_DIR) $(ROOT)/bin/ $(ROOT)/sbin/
|
||||
$(INSTALL_DIR) $(ROOT)/usr/bin/
|
||||
for i in $(BIN); do \
|
||||
$(INSTALL_EXEC) $$i $(ROOT)/bin/ ; \
|
||||
done
|
||||
for i in $(SBIN); do \
|
||||
$(INSTALL_EXEC) $$i $(ROOT)/sbin/ ; \
|
||||
done
|
||||
for i in $(USRBIN); do \
|
||||
$(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
|
||||
done
|
||||
# $(INSTALL_DIR) $(ROOT)/etc/
|
||||
# $(INSTALL_EXEC) ../doc/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_DIR) $(ROOT)/usr/include/
|
||||
$(INSTALL_DATA) initreq.h $(ROOT)/usr/include/
|
||||
$(INSTALL_DIR) $(ROOT)$(MANDIR)/man1/
|
||||
$(INSTALL_DIR) $(ROOT)$(MANDIR)/man5/
|
||||
$(INSTALL_DIR) $(ROOT)$(MANDIR)/man8/
|
||||
for man in $(MAN1); do \
|
||||
$(INSTALL_DATA) ../man/$$man $(ROOT)$(MANDIR)/man1/; \
|
||||
sed -i "1{ $(MANDB); }" $(ROOT)$(MANDIR)/man1/$$man ; \
|
||||
done
|
||||
for man in $(MAN5); do \
|
||||
$(INSTALL_DATA) ../man/$$man $(ROOT)$(MANDIR)/man5/; \
|
||||
sed -i "1{ $(MANDB); }" $(ROOT)$(MANDIR)/man5/$$man ; \
|
||||
done
|
||||
for man in $(MAN8); do \
|
||||
$(INSTALL_DATA) ../man/$$man $(ROOT)$(MANDIR)/man8/; \
|
||||
sed -i "1{ $(MANDB); }" $(ROOT)$(MANDIR)/man8/$$man ; \
|
||||
done
|
||||
ifeq ($(ROOT),)
|
||||
#
|
||||
# This part is skipped on Debian systems, the
|
||||
# debian.preinst script takes care of it.
|
||||
@if [ ! -p /run/initctl ]; then \
|
||||
echo "Creating /run/initctl"; \
|
||||
rm -f /run/initctl; \
|
||||
mknod -m 600 /run/initctl p; fi
|
||||
endif
|
|
@ -0,0 +1,738 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef __linux__
|
||||
#include <pty.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <termios.h>
|
||||
#include <libutil.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#include "bootlogd.h"
|
||||
|
||||
#define MAX_CONSOLES 16
|
||||
#define KERNEL_COMMAND_LENGTH 4096
|
||||
|
||||
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 real_cons {
|
||||
char name[1024];
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
This function does not appear to be called anymore. Commenting it
|
||||
out for now, can probably be removed entirely in the future.
|
||||
|
||||
static int findtty(char *res, const char *startdir, int rlen, dev_t dev)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
struct stat st;
|
||||
int r = -1;
|
||||
char *olddir = getcwd(NULL, 0);
|
||||
|
||||
if (chdir(startdir) < 0 || (dir = opendir(".")) == NULL) {
|
||||
int msglen = strlen(startdir) + 11;
|
||||
char *msg = malloc(msglen);
|
||||
snprintf(msg, msglen, "bootlogd: %s", startdir);
|
||||
perror(msg);
|
||||
free(msg);
|
||||
chdir(olddir);
|
||||
return -1;
|
||||
}
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
if (lstat(ent->d_name, &st) != 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode)
|
||||
&& 0 != strcmp(".", ent->d_name)
|
||||
&& 0 != strcmp("..", ent->d_name)) {
|
||||
char *path = malloc(rlen);
|
||||
snprintf(path, rlen, "%s/%s", startdir, ent->d_name);
|
||||
r = findtty(res, path, rlen, dev);
|
||||
free(path);
|
||||
if (0 == r) {
|
||||
closedir(dir);
|
||||
chdir(olddir);
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!S_ISCHR(st.st_mode))
|
||||
continue;
|
||||
if (st.st_rdev == dev) {
|
||||
if ( (int) (strlen(ent->d_name) + strlen(startdir) + 1) >= rlen) {
|
||||
fprintf(stderr, "bootlogd: console device name too long\n");
|
||||
closedir(dir);
|
||||
chdir(olddir);
|
||||
return -1;
|
||||
} else {
|
||||
snprintf(res, rlen, "%s/%s", startdir, ent->d_name);
|
||||
closedir(dir);
|
||||
chdir(olddir);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
chdir(olddir);
|
||||
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) 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(s). Assume that stdin is connected to
|
||||
* the console device (/dev/console).
|
||||
*/
|
||||
int consolenames(struct real_cons *cons, int max_consoles)
|
||||
{
|
||||
#ifdef TIOCGDEV
|
||||
/* This appears to be unused. unsigned int kdev; */
|
||||
#endif
|
||||
struct stat st, st2;
|
||||
char buf[KERNEL_COMMAND_LENGTH];
|
||||
char *p;
|
||||
int didmount = 0;
|
||||
int n;
|
||||
int fd;
|
||||
int considx, num_consoles = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Read /proc/cmdline.
|
||||
*/
|
||||
stat("/", &st);
|
||||
if (stat("/proc", &st2) < 0) {
|
||||
perror("bootlogd: /proc");
|
||||
return 0;
|
||||
}
|
||||
if (st.st_dev == st2.st_dev) {
|
||||
if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
|
||||
perror("bootlogd: mount /proc");
|
||||
return -1;
|
||||
}
|
||||
didmount = 1;
|
||||
}
|
||||
|
||||
n = -1;
|
||||
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
|
||||
perror("bootlogd: /proc/cmdline");
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
if ((n = read(fd, buf, KERNEL_COMMAND_LENGTH - 1)) < 0)
|
||||
perror("bootlogd: /proc/cmdline");
|
||||
close(fd);
|
||||
}
|
||||
if (didmount) umount("/proc");
|
||||
|
||||
if (n < 0) return 0;
|
||||
|
||||
/*
|
||||
* OK, so find console= in /proc/cmdline.
|
||||
* Parse in reverse, opening as we go.
|
||||
*/
|
||||
p = buf + n;
|
||||
*p-- = 0;
|
||||
while (p >= buf) {
|
||||
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
|
||||
*p-- = 0;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(p, "console=", 8) == 0 &&
|
||||
isconsole(p + 8, cons[num_consoles].name, sizeof(cons[num_consoles].name))) {
|
||||
/*
|
||||
* Suppress duplicates
|
||||
*/
|
||||
for (considx = 0; considx < num_consoles; considx++) {
|
||||
if (!strcmp(cons[num_consoles].name, cons[considx].name)) {
|
||||
goto dontuse;
|
||||
}
|
||||
}
|
||||
|
||||
num_consoles++;
|
||||
if (num_consoles >= max_consoles) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
dontuse:
|
||||
p--;
|
||||
}
|
||||
|
||||
if (num_consoles > 0) return num_consoles;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Okay, no console on the command line -
|
||||
* guess the default console.
|
||||
*/
|
||||
for (n = 0; defcons[n]; n++)
|
||||
if (isconsole(defcons[n], cons[0].name, sizeof(cons[0].name)))
|
||||
return 1;
|
||||
|
||||
fprintf(stderr, "bootlogd: cannot deduce real console device\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write data and make sure it's on disk.
|
||||
*/
|
||||
void writelog(FILE *fp, unsigned char *ptr, int len, int print_escape_characters)
|
||||
{
|
||||
int dosync = 0;
|
||||
int i;
|
||||
static int first_run = 1;
|
||||
static int inside_esc = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int ignore = 0;
|
||||
|
||||
/* prepend date to every line */
|
||||
if (*(ptr-1) == '\n' || first_run) {
|
||||
time_t t;
|
||||
char *s;
|
||||
time(&t);
|
||||
s = ctime(&t);
|
||||
fprintf(fp, "%.24s: ", s);
|
||||
dosync = 1;
|
||||
first_run = 0;
|
||||
}
|
||||
|
||||
/* remove escape sequences, but do it in a way that allows us to stop
|
||||
* in the middle in case the string was cut off */
|
||||
if (! print_escape_characters)
|
||||
{
|
||||
if (inside_esc == 1) {
|
||||
/* first '[' is special because if we encounter it again, it should be considered the final byte */
|
||||
if (*ptr == '[') {
|
||||
/* multi char sequence */
|
||||
ignore = 1;
|
||||
inside_esc = 2;
|
||||
} else {
|
||||
/* single char sequence */
|
||||
if (*ptr >= 64 && *ptr <= 95) {
|
||||
ignore = 1;
|
||||
}
|
||||
inside_esc = 0;
|
||||
}
|
||||
} else if (inside_esc == 2) {
|
||||
switch (*ptr) {
|
||||
case '0' ... '9': /* intermediate chars of escape sequence */
|
||||
case ';':
|
||||
case 32 ... 47:
|
||||
if (inside_esc) {
|
||||
ignore = 1;
|
||||
}
|
||||
break;
|
||||
case 64 ... 126: /* final char of escape sequence */
|
||||
if (inside_esc) {
|
||||
ignore = 1;
|
||||
inside_esc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (*ptr) {
|
||||
case '\r':
|
||||
ignore = 1;
|
||||
break;
|
||||
case 27: /* ESC */
|
||||
ignore = 1;
|
||||
inside_esc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* end of if we should filter escape characters */
|
||||
|
||||
if (!ignore) {
|
||||
fwrite(ptr, sizeof(char), 1, fp);
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
if (dosync) {
|
||||
fflush(fp);
|
||||
if (syncalot) {
|
||||
fdatasync(fileno(fp));
|
||||
}
|
||||
}
|
||||
|
||||
outptr += len;
|
||||
if (outptr >= endptr)
|
||||
outptr = ringbuf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print usage message and exit.
|
||||
*/
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: bootlogd [-v] [-r] [-d] [-e] [-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 *p;
|
||||
char *logfile;
|
||||
char *pidfile;
|
||||
int rotate;
|
||||
int dontfork;
|
||||
int ptm, pts;
|
||||
/* int realfd; -- this is now unused */
|
||||
int n, m, i;
|
||||
int todo;
|
||||
#ifndef __linux__ /* BSD-style ioctl needs an argument. */
|
||||
int on = 1;
|
||||
#endif
|
||||
int considx;
|
||||
struct real_cons cons[MAX_CONSOLES];
|
||||
int num_consoles, consoles_left;
|
||||
int print_escape_sequence = 0;
|
||||
fp = NULL;
|
||||
logfile = LOGFILE;
|
||||
pidfile = NULL;
|
||||
rotate = 0;
|
||||
dontfork = 0;
|
||||
|
||||
while ((i = getopt(argc, argv, "cdesl:p:rv")) != EOF) switch(i) {
|
||||
case 'l':
|
||||
logfile = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
rotate = 1;
|
||||
break;
|
||||
case 'v':
|
||||
printf("bootlogd - %s\n", VERSION);
|
||||
exit(0);
|
||||
break;
|
||||
case 'p':
|
||||
pidfile = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
createlogfile = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dontfork = 1;
|
||||
break;
|
||||
case 'e':
|
||||
print_escape_sequence = 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", realcons, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
if ((num_consoles = consolenames(cons, MAX_CONSOLES)) <= 0)
|
||||
return 1;
|
||||
consoles_left = num_consoles;
|
||||
for (considx = 0; considx < num_consoles; considx++) {
|
||||
if (strcmp(cons[considx].name, "/dev/tty0") == 0)
|
||||
strcpy(cons[considx].name, "/dev/tty1");
|
||||
if (strcmp(cons[considx].name, "/dev/vc/0") == 0)
|
||||
strcpy(cons[considx].name, "/dev/vc/1");
|
||||
|
||||
if ((cons[considx].fd = open_nb(cons[considx].name)) < 0) {
|
||||
fprintf(stderr, "bootlogd: %s: %s\n",
|
||||
cons[considx].name, strerror(errno));
|
||||
consoles_left--;
|
||||
}
|
||||
}
|
||||
if (!consoles_left)
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
(void)ioctl(0, TIOCCONS, NULL);
|
||||
/* 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
|
||||
#ifdef __linux__
|
||||
if (ioctl(pts, TIOCCONS, NULL) < 0)
|
||||
#else /* BSD usage of ioctl TIOCCONS. */
|
||||
if (ioctl(pts, TIOCCONS, &on) < 0)
|
||||
#endif
|
||||
{
|
||||
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 devices.
|
||||
*/
|
||||
for (considx = 0; considx < num_consoles; considx++) {
|
||||
if (cons[considx].fd < 0) continue;
|
||||
m = n;
|
||||
p = inptr;
|
||||
while (m > 0) {
|
||||
i = write(cons[considx].fd, p, m);
|
||||
if (i >= 0) {
|
||||
m -= i;
|
||||
p += i;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Handle EIO (somebody hung
|
||||
* up our filedescriptor)
|
||||
*/
|
||||
cons[considx].fd = write_err(pts,
|
||||
cons[considx].fd,
|
||||
cons[considx].name, errno);
|
||||
if (cons[considx].fd >= 0) continue;
|
||||
/*
|
||||
* If this was the last console,
|
||||
* generate a fake signal
|
||||
*/
|
||||
if (--consoles_left <= 0) got_signal = 1;
|
||||
break;
|
||||
} /* end of while */
|
||||
} /* end of going through all consoles */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
} /* end of got data from read */
|
||||
} /* end of checking select for new data */
|
||||
|
||||
/*
|
||||
* 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, (unsigned char *)outptr, todo, print_escape_sequence);
|
||||
} /* end of while waiting for signal */
|
||||
|
||||
if (fp) {
|
||||
if (!didnl) fputc('\n', fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
close(pts);
|
||||
close(ptm);
|
||||
for (considx = 0; considx < num_consoles; considx++) {
|
||||
close(cons[considx].fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef LOGFILE
|
||||
#define LOGFILE "/var/log/boot"
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
* consoles.c Routines to detect the system consoles
|
||||
*
|
||||
* Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
* Author: Werner Fink <werner@suse.de>
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ttydefaults.h>
|
||||
#ifdef __linux__
|
||||
# include <sys/vt.h>
|
||||
# include <sys/kd.h>
|
||||
# include <linux/serial.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "consoles.h"
|
||||
|
||||
#ifdef __linux__
|
||||
# include <linux/major.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
|
||||
# ifndef typeof
|
||||
# define typeof __typeof__
|
||||
# endif
|
||||
# ifndef restrict
|
||||
# define restrict __restrict__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
|
||||
|
||||
struct console *consoles;
|
||||
|
||||
/*
|
||||
* Read and allocate one line from file,
|
||||
* the caller has to free the result
|
||||
*/
|
||||
static
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__nonnull__))
|
||||
#endif
|
||||
char *oneline(const char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
char *ret = (char*)0, *nl;
|
||||
size_t len = 0;
|
||||
|
||||
if ((fp = fopen(file, "re")) == (FILE*)0)
|
||||
goto err;
|
||||
if (getline(&ret, &len, fp) < 0)
|
||||
goto out;
|
||||
if (len)
|
||||
ret[len-1] = '\0';
|
||||
if ((nl = strchr(ret, '\n')))
|
||||
*nl = '\0';
|
||||
out:
|
||||
fclose(fp);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Read and determine active attribute for tty below
|
||||
* /sys/class/tty, the caller has to free the result.
|
||||
*/
|
||||
static
|
||||
__attribute__((__malloc__))
|
||||
char *actattr(const char *tty)
|
||||
{
|
||||
char *ret = (char*)0;
|
||||
char *path;
|
||||
|
||||
if (!tty || *tty == '\0')
|
||||
goto err;
|
||||
|
||||
if (asprintf(&path, "/sys/class/tty/%s/active", tty) < 0)
|
||||
goto err;
|
||||
|
||||
if ((ret = oneline(path)) == (char*)0)
|
||||
goto out;
|
||||
out:
|
||||
free(path);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and determine device attribute for tty below
|
||||
* /sys/class/tty.
|
||||
*/
|
||||
static
|
||||
dev_t devattr(const char *tty)
|
||||
{
|
||||
unsigned int maj, min;
|
||||
dev_t dev = 0;
|
||||
char *path, *value;
|
||||
|
||||
if (!tty || *tty == '\0')
|
||||
goto err;
|
||||
|
||||
if (asprintf(&path, "/sys/class/tty/%s/dev", tty) < 0)
|
||||
goto err;
|
||||
|
||||
if ((value = oneline(path)) == (char*)0)
|
||||
goto out;
|
||||
|
||||
if (sscanf(value, "%u:%u", &maj, &min) == 2)
|
||||
dev = makedev(maj, min);
|
||||
free(value);
|
||||
out:
|
||||
free(path);
|
||||
err:
|
||||
return dev;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
/*
|
||||
* Search below /dev for the characer device in
|
||||
* the local `dev_t comparedev' variable.
|
||||
*/
|
||||
static dev_t comparedev;
|
||||
static
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__nonnull__,__malloc__,__hot__))
|
||||
#endif
|
||||
char* scandev(DIR *dir)
|
||||
{
|
||||
char *name = (char*)0;
|
||||
struct dirent *dent;
|
||||
int fd;
|
||||
|
||||
fd = dirfd(dir);
|
||||
rewinddir(dir);
|
||||
while ((dent = readdir(dir))) {
|
||||
char *path;
|
||||
struct stat st;
|
||||
if (fstatat(fd, dent->d_name, &st, 0) < 0)
|
||||
continue;
|
||||
if (!S_ISCHR(st.st_mode))
|
||||
continue;
|
||||
if (comparedev != st.st_rdev)
|
||||
continue;
|
||||
if (asprintf(&path, "/dev/%s", dent->d_name) < 0)
|
||||
continue;
|
||||
name = realpath(path, NULL);
|
||||
free(path);
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Default control characters for an unknown terminal line.
|
||||
*/
|
||||
static
|
||||
struct chardata initcp = {
|
||||
CERASE,
|
||||
CKILL,
|
||||
CTRL('r'),
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate an aligned `struct console' memory area,
|
||||
* initialize its default values, and append it to
|
||||
* the global linked list.
|
||||
*/
|
||||
|
||||
static int concount; /* Counter for console IDs */
|
||||
|
||||
static
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__nonnull__,__hot__))
|
||||
#endif
|
||||
void consalloc(char * name)
|
||||
{
|
||||
struct console *restrict tail;
|
||||
|
||||
if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
|
||||
perror("memory allocation");
|
||||
|
||||
tail->next = (struct console*)0;
|
||||
tail->tty = name;
|
||||
|
||||
tail->file = (FILE*)0;
|
||||
tail->flags = 0;
|
||||
tail->fd = -1;
|
||||
tail->id = concount++;
|
||||
tail->pid = 0;
|
||||
memset(&tail->tio, 0, sizeof(tail->tio));
|
||||
memcpy(&tail->cp, &initcp, sizeof(struct chardata));
|
||||
|
||||
if (!consoles)
|
||||
consoles = tail;
|
||||
else
|
||||
consoles->next = tail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to detect the real device(s) used for the system console
|
||||
* /dev/console if but only if /dev/console is used. On Linux
|
||||
* this can be more than one device, e.g. a serial line as well
|
||||
* as a virtual console as well as a simple printer.
|
||||
*
|
||||
* Returns 1 if stdout and stderr should be reconnected and 0
|
||||
* otherwise.
|
||||
*/
|
||||
int detect_consoles(const char *device, int fallback)
|
||||
{
|
||||
int fd, ret = 0;
|
||||
#ifdef __linux__
|
||||
char *attrib, *cmdline;
|
||||
FILE *fc;
|
||||
#endif
|
||||
if (!device || *device == '\0')
|
||||
fd = dup(fallback);
|
||||
else {
|
||||
fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
DIR *dir;
|
||||
char *name;
|
||||
struct stat st;
|
||||
#ifdef TIOCGDEV
|
||||
unsigned int devnum;
|
||||
#endif
|
||||
|
||||
if (fstat(fd, &st) < 0) {
|
||||
close(fd);
|
||||
goto fallback;
|
||||
}
|
||||
comparedev = st.st_rdev;
|
||||
|
||||
if (ret && (fstat(fallback, &st) < 0 || comparedev != st.st_rdev))
|
||||
dup2(fd, fallback);
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Check if the device detection for Linux system console should be used.
|
||||
*/
|
||||
if (comparedev == makedev(TTYAUX_MAJOR, 0)) { /* /dev/tty */
|
||||
close(fd);
|
||||
device = "/dev/tty";
|
||||
goto fallback;
|
||||
}
|
||||
if (comparedev == makedev(TTYAUX_MAJOR, 1)) { /* /dev/console */
|
||||
close(fd);
|
||||
goto console;
|
||||
}
|
||||
if (comparedev == makedev(TTYAUX_MAJOR, 2)) { /* /dev/ptmx */
|
||||
close(fd);
|
||||
device = "/dev/tty";
|
||||
goto fallback;
|
||||
}
|
||||
if (comparedev == makedev(TTY_MAJOR, 0)) { /* /dev/tty0 */
|
||||
struct vt_stat vt;
|
||||
if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
|
||||
close(fd);
|
||||
goto fallback;
|
||||
}
|
||||
comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
|
||||
}
|
||||
#endif
|
||||
#ifdef TIOCGDEV
|
||||
if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
|
||||
close(fd);
|
||||
goto fallback;
|
||||
}
|
||||
comparedev = (dev_t)devnum;
|
||||
#endif
|
||||
close(fd);
|
||||
dir = opendir("/dev");
|
||||
if (!dir)
|
||||
goto fallback;
|
||||
name = scandev(dir);
|
||||
if (name)
|
||||
consalloc(name);
|
||||
closedir(dir);
|
||||
if (!consoles)
|
||||
goto fallback;
|
||||
return ret;
|
||||
}
|
||||
#ifdef __linux__
|
||||
console:
|
||||
/*
|
||||
* Detection of devices used for Linux system consolei using
|
||||
* the /proc/consoles API with kernel 2.6.38 and higher.
|
||||
*/
|
||||
if ((fc = fopen("/proc/consoles", "re"))) {
|
||||
char fbuf[16];
|
||||
int maj, min;
|
||||
DIR *dir;
|
||||
dir = opendir("/dev");
|
||||
if (!dir) {
|
||||
fclose(fc);
|
||||
goto fallback;
|
||||
}
|
||||
while ((fscanf(fc, "%*s %*s (%[^)]) %d:%d", &fbuf[0], &maj, &min) == 3)) {
|
||||
char * name;
|
||||
|
||||
if (!strchr(fbuf, 'E'))
|
||||
continue;
|
||||
comparedev = makedev(maj, min);
|
||||
|
||||
name = scandev(dir);
|
||||
if (!name)
|
||||
continue;
|
||||
consalloc(name);
|
||||
}
|
||||
closedir(dir);
|
||||
fclose(fc);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Detection of devices used for Linux system console using
|
||||
* the sysfs /sys/class/tty/ API with kernel 2.6.37 and higher.
|
||||
*/
|
||||
if ((attrib = actattr("console"))) {
|
||||
char *words = attrib, *token;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir("/dev");
|
||||
if (!dir) {
|
||||
free(attrib);
|
||||
goto fallback;
|
||||
}
|
||||
while ((token = strsep(&words, " \t\r\n"))) {
|
||||
char * name;
|
||||
|
||||
if (*token == '\0')
|
||||
continue;
|
||||
comparedev = devattr(token);
|
||||
if (comparedev == makedev(TTY_MAJOR, 0)) {
|
||||
char *tmp = actattr(token);
|
||||
if (!tmp)
|
||||
continue;
|
||||
comparedev = devattr(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
name = scandev(dir);
|
||||
if (!name)
|
||||
continue;
|
||||
consalloc(name);
|
||||
}
|
||||
closedir(dir);
|
||||
free(attrib);
|
||||
if (!consoles)
|
||||
goto fallback;
|
||||
return ret;
|
||||
|
||||
}
|
||||
/*
|
||||
* Detection of devices used for Linux system console using
|
||||
* kernel parameter on the kernels command line.
|
||||
*/
|
||||
if ((cmdline = oneline("/proc/cmdline"))) {
|
||||
char *words= cmdline, *token;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir("/dev");
|
||||
if (!dir) {
|
||||
free(cmdline);
|
||||
goto fallback;
|
||||
}
|
||||
while ((token = strsep(&words, " \t\r\n"))) {
|
||||
#ifdef TIOCGDEV
|
||||
unsigned int devnum;
|
||||
#else
|
||||
struct vt_stat vt;
|
||||
struct stat st;
|
||||
#endif
|
||||
char *colon, *name;
|
||||
|
||||
if (*token != 'c')
|
||||
continue;
|
||||
|
||||
if (strncmp(token, "console=", 8) != 0)
|
||||
continue;
|
||||
token += 8;
|
||||
|
||||
if (strcmp(token, "brl") == 0)
|
||||
token += 4;
|
||||
if ((colon = strchr(token, ',')))
|
||||
*colon = '\0';
|
||||
|
||||
if (asprintf(&name, "/dev/%s", token) < 0)
|
||||
continue;
|
||||
|
||||
if ((fd = open(name, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)) < 0) {
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
free(name);
|
||||
#ifdef TIOCGDEV
|
||||
if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
comparedev = (dev_t)devnum;
|
||||
#else
|
||||
if (fstat(fd, &st) < 0) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
comparedev = st.st_rdev;
|
||||
if (comparedev == makedev(TTY_MAJOR, 0)) {
|
||||
if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
|
||||
}
|
||||
#endif
|
||||
close(fd);
|
||||
|
||||
name = scandev(dir);
|
||||
if (!name)
|
||||
continue;
|
||||
consalloc(name);
|
||||
}
|
||||
closedir(dir);
|
||||
free(cmdline);
|
||||
/*
|
||||
* Detection of the device used for Linux system console using
|
||||
* the ioctl TIOCGDEV if available (e.g. official 2.6.38).
|
||||
*/
|
||||
if (!consoles) {
|
||||
#ifdef TIOCGDEV
|
||||
unsigned int devnum;
|
||||
const char *name;
|
||||
|
||||
if (!device || *device == '\0')
|
||||
fd = dup(fallback);
|
||||
else fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
|
||||
|
||||
if (fd < 0)
|
||||
goto fallback;
|
||||
|
||||
if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
|
||||
close(fd);
|
||||
goto fallback;
|
||||
}
|
||||
comparedev = (dev_t)devnum;
|
||||
close(fd);
|
||||
|
||||
if (device && *device != '\0')
|
||||
name = device;
|
||||
else name = ttyname(fallback);
|
||||
|
||||
if (!name)
|
||||
name = "/dev/tty1";
|
||||
|
||||
consalloc(strdup(name));
|
||||
if (consoles) {
|
||||
if (!device || *device == '\0')
|
||||
consoles->fd = fallback;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
goto fallback;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* __linux __ */
|
||||
fallback:
|
||||
if (fallback >= 0) {
|
||||
const char *name;
|
||||
|
||||
if (device && *device != '\0')
|
||||
name = device;
|
||||
else name = ttyname(fallback);
|
||||
|
||||
if (!name)
|
||||
name = "/dev/tty";
|
||||
|
||||
consalloc(strdup(name));
|
||||
if (consoles)
|
||||
consoles->fd = fallback;
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* consoles.h Header file for routines to detect the system consoles
|
||||
*
|
||||
* Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
* Author: Werner Fink <werner@suse.de>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
|
||||
struct chardata {
|
||||
uint8_t erase;
|
||||
uint8_t kill;
|
||||
uint8_t eol;
|
||||
uint8_t parity;
|
||||
};
|
||||
struct console {
|
||||
char *tty;
|
||||
FILE *file;
|
||||
uint32_t flags;
|
||||
int fd, id;
|
||||
#define CON_SERIAL 0x0001
|
||||
#define CON_NOTTY 0x0002
|
||||
pid_t pid;
|
||||
struct chardata cp;
|
||||
struct termios tio;
|
||||
struct console *next;
|
||||
};
|
||||
extern struct console *consoles;
|
||||
extern int detect_consoles(const char *, int);
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <paths.h>
|
||||
|
||||
#ifndef _PATH_DEV
|
||||
# define _PATH_DEV "/dev/"
|
||||
#endif
|
||||
#ifndef HOST_NAME_MAX
|
||||
# define HOST_NAME_MAX 255
|
||||
#endif
|
||||
|
||||
static sigjmp_buf jbuf;
|
||||
|
||||
/*
|
||||
* Alarm handler
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
# ifdef __GNUC__
|
||||
static void handler(int arg __attribute__((unused)))
|
||||
# else
|
||||
static void handler(int arg)
|
||||
# endif
|
||||
{
|
||||
siglongjmp(jbuf, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print a text, escape all characters not in Latin-1.
|
||||
*/
|
||||
static void feputs(const 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 {
|
||||
/* Using variable number of data parameters in one
|
||||
function makes the Clang compiler cry. -- Jesse
|
||||
sprintf(uidbuf, uid ? "uid %d" : "root", (int)uid);
|
||||
*/
|
||||
if (uid)
|
||||
sprintf(uidbuf, "uid %d", (int) uid);
|
||||
else
|
||||
sprintf(uidbuf, "root");
|
||||
}
|
||||
|
||||
if ((tty = ttyname(0)) != NULL) {
|
||||
const size_t plen = strlen(_PATH_DEV);
|
||||
if (strncmp(tty, _PATH_DEV, plen) == 0) {
|
||||
tty += plen;
|
||||
if (tty[0] == '/')
|
||||
tty++;
|
||||
}
|
||||
snprintf(ttynm, sizeof(ttynm), "(%.*s) ",
|
||||
UT_LINESIZE, 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(const char *text, int remote)
|
||||
{
|
||||
FILE *tp;
|
||||
struct sigaction sa;
|
||||
struct utmp *utmp;
|
||||
time_t t;
|
||||
char term[UT_LINESIZE+ strlen(_PATH_DEV) + 1];
|
||||
char line[81];
|
||||
char hostname[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),
|
||||
"\r\nRemote broadcast message (%s):\r\n\r\n",
|
||||
date);
|
||||
} else {
|
||||
snprintf(line, sizeof(line),
|
||||
"\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, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
|
||||
term[0] = 0;
|
||||
strncat(term, utmp->ut_line, sizeof(term)-1);
|
||||
} else
|
||||
snprintf(term, sizeof(term), _PATH_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);
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/* fstab-decode(8).
|
||||
|
||||
Copyright (c) 2006 Red Hat, Inc. All rights reserved.
|
||||
|
||||
This copyrighted material is made available to anyone wishing to use, modify,
|
||||
copy, or redistribute it subject to the terms and conditions of the GNU General
|
||||
Public License v.2.
|
||||
|
||||
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.
|
||||
|
||||
Author: Miloslav Trmac <mitr@redhat.com> */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Decode the fstab-encoded string in place. */
|
||||
static void
|
||||
decode(char *s)
|
||||
{
|
||||
const char *src;
|
||||
char *dest;
|
||||
|
||||
src = s;
|
||||
dest = s;
|
||||
while (*src != '\0') {
|
||||
if (*src != '\\')
|
||||
*dest = *src++;
|
||||
else {
|
||||
static const struct repl {
|
||||
char orig[4];
|
||||
size_t len;
|
||||
char new;
|
||||
} repls[] = {
|
||||
#define R(X, Y) { X, sizeof(X) - 1, Y }
|
||||
R("\\", '\\'),
|
||||
R("011", '\t'),
|
||||
R("012", '\n'),
|
||||
R("040", ' '),
|
||||
R("134", '\\')
|
||||
#undef R
|
||||
};
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof (repls) / sizeof (repls[0]);
|
||||
i++) {
|
||||
if (memcmp(src + 1, repls[i].orig,
|
||||
repls[i].len) == 0) {
|
||||
*dest = repls[i].new;
|
||||
src += 1 + repls[i].len;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
*dest = *src++;
|
||||
found:
|
||||
;
|
||||
}
|
||||
dest++;
|
||||
}
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: fstab-decode command [arguments]\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (i = 2; i < (size_t)argc; i++)
|
||||
decode(argv[i]);
|
||||
execvp(argv[1], argv + 1);
|
||||
fprintf(stderr, "fstab-decode: %s: %s\n", argv[1], strerror(errno));
|
||||
return 127;
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "runlevellog.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 int hdflush(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.
|
||||
* Or the /var/run/runlevel log.
|
||||
*/
|
||||
int get_runlevel(void)
|
||||
{
|
||||
struct utmp *ut;
|
||||
char *r;
|
||||
int runlevel, status;
|
||||
|
||||
#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();
|
||||
|
||||
/* Did not find utmp entry, try to read from log file */
|
||||
status = Read_Runlevel_Log(&runlevel);
|
||||
if (status)
|
||||
return runlevel;
|
||||
|
||||
/* 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, int should_poweroff, char *tm)
|
||||
{
|
||||
char *args[9];
|
||||
int i = 0;
|
||||
|
||||
args[i++] = "shutdown";
|
||||
args[i++] = fl;
|
||||
if ( (! strcmp(fl, "-h") ) && (should_poweroff) )
|
||||
args[i++] = "-P";
|
||||
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);
|
||||
}
|
||||
|
||||
if (chdir("/")) {
|
||||
fprintf(stderr, "%s: chdir(/): %m\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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", do_poweroff, 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();
|
||||
/* Sync should be fine on its own for making sure data is written.
|
||||
We probably call shutdown after this anyway to clean up.
|
||||
-- Jesse
|
||||
sleep(2);
|
||||
*/
|
||||
}
|
||||
|
||||
if (do_ifdown)
|
||||
(void)ifdown();
|
||||
|
||||
if (do_hddown)
|
||||
(void)hddown();
|
||||
else
|
||||
(void)hdflush();
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#ifndef USE_SYSFS
|
||||
# define USE_SYSFS 1
|
||||
#endif
|
||||
#if defined(USE_SYSFS) && (USE_SYSFS == 1)
|
||||
/*
|
||||
* 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_disk() */
|
||||
#define DISK_IS_IDE 0x00000001
|
||||
#define DISK_IS_SATA 0x00000002
|
||||
#define DISK_EXTFLUSH 0x00000004
|
||||
#define DISK_REMOVABLE 0x00000008
|
||||
#define DISK_MANAGED 0x00000010
|
||||
#define DISK_FLUSHONLY 0x00000020
|
||||
|
||||
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;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
|
||||
if (0 == (long)fp || -1 == (long)fp) {
|
||||
if (-1 == (long)fp)
|
||||
goto empty; /* error */
|
||||
continue; /* no entry `removable' */
|
||||
}
|
||||
|
||||
ret = getc(fp);
|
||||
fclose(fp);
|
||||
|
||||
if (ret != '0')
|
||||
(*flags) |= DISK_REMOVABLE;
|
||||
|
||||
if (d->d_name[0] == 'h') {
|
||||
if ((*flags) & DISK_REMOVABLE)
|
||||
continue; /* not a hard disk */
|
||||
|
||||
(*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 >= (int)sizeof(buf)) || (ret < 0))
|
||||
goto empty; /* error */
|
||||
|
||||
ret = readlink(buf, lnk, sizeof(lnk));
|
||||
if (ret >= (int)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 */
|
||||
|
||||
fp = hdopen(SYS_CLASS "/%s/manage_start_stop", ptr);
|
||||
if (0 == (long)fp || -1 == (long)fp) {
|
||||
if (-1 == (long)fp)
|
||||
goto empty; /* error */
|
||||
} else {
|
||||
ret = getc(fp);
|
||||
fclose(fp);
|
||||
|
||||
if (ret != '0') {
|
||||
(*flags) |= DISK_MANAGED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fp = hdopen(SYS_BLK "/%s/device/vendor", d->d_name);
|
||||
if (0 == (long)fp || -1 == (long)fp) {
|
||||
if (-1 == (long)fp)
|
||||
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)) == 0) {
|
||||
if ((*flags) & DISK_REMOVABLE)
|
||||
continue; /* not a hard 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 (((*flags) & DISK_REMOVABLE) == 0)
|
||||
continue; /* Seems to be a real SCSI disk */
|
||||
|
||||
if ((ret = flush_cache_ext(d->d_name))) {
|
||||
if (ret < 0)
|
||||
goto empty;
|
||||
(*flags) |= DISK_EXTFLUSH;
|
||||
}
|
||||
break; /* Removable disk like USB stick to shutdown */
|
||||
}
|
||||
}
|
||||
if (d == (struct dirent*)0)
|
||||
goto empty;
|
||||
return d->d_name;
|
||||
empty:
|
||||
return (char*)0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put an IDE/SCSI/SATA disk in standby mode.
|
||||
* Code stolen from hdparm.c
|
||||
*/
|
||||
static int do_standby_disk(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 >= (int)sizeof(buf)) || (ret < 0))
|
||||
return -1;
|
||||
|
||||
if ((fd = open(buf, O_RDWR|O_NONBLOCK)) < 0)
|
||||
return -1;
|
||||
|
||||
switch (flags & DISK_EXTFLUSH) {
|
||||
case DISK_EXTFLUSH:
|
||||
if ((ret = ioctl(fd, HDIO_DRIVE_CMD, &flush1)) == 0)
|
||||
break;
|
||||
/* Else Fall through */
|
||||
/* Extend flush rejected, try standard flush */
|
||||
default:
|
||||
ret = ioctl(fd, HDIO_DRIVE_CMD, &flush2) &&
|
||||
ioctl(fd, BLKFLSBUF);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((flags & DISK_FLUSHONLY) == 0x0) {
|
||||
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_disk(disk, flags);
|
||||
|
||||
return closedir(blk);
|
||||
}
|
||||
|
||||
/*
|
||||
* List all disks and cause them to flush their buffers.
|
||||
*/
|
||||
int hdflush(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_disk(disk, (flags|DISK_FLUSHONLY));
|
||||
|
||||
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. Return 0 if the file didn't exist, or (FILE*)-1 if
|
||||
* something else went wrong.
|
||||
*/
|
||||
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 >= (int)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 (0 == (long)fp || -1 == (long)fp) {
|
||||
if (-1 == (long)fp)
|
||||
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 >= (int)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);
|
||||
}
|
||||
|
||||
int hdflush(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ! USE_SYSFS */
|
||||
#else /* __linux__ */
|
||||
|
||||
int hddown(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdflush(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#ifdef STANDALONE
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return (hddown() == 0);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define MAX_IFS 64
|
||||
|
||||
/* XXX: Ideally this would get detected at configure time... */
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#define HAVE_SOCKADDR_SA_LEN 1
|
||||
#endif
|
||||
|
||||
#ifndef _SIZEOF_ADDR_IFREQ
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
#define _SIZEOF_ADDR_IFREQ(ifr) \
|
||||
((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
|
||||
(sizeof((ifr).ifr_name) + (ifr).ifr_addr.sa_len) : \
|
||||
sizeof(struct ifreq))
|
||||
#else
|
||||
#define _SIZEOF_ADDR_IFREQ(ifr) sizeof(struct ifreq)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
char ifr_buf[sizeof(struct ifreq) * MAX_IFS];
|
||||
char *ifr_end;
|
||||
struct ifconf ifc;
|
||||
int fd;
|
||||
int shaper;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
fprintf(stderr, "ifdown: ");
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
ifc.ifc_len = sizeof(ifr_buf);
|
||||
ifc.ifc_buf = ifr_buf;
|
||||
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
|
||||
fprintf(stderr, "ifdown: ");
|
||||
perror("SIOCGIFCONF");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
ifr_end = ifr_buf + ifc.ifc_len;
|
||||
|
||||
for (shaper = 1; shaper >= 0; shaper--) {
|
||||
char *ifr_next = ifr_buf;
|
||||
|
||||
while (ifr_next < ifr_end) {
|
||||
struct ifreq *ifr;
|
||||
int flags;
|
||||
|
||||
ifr = (struct ifreq *)ifr_next;
|
||||
ifr_next += _SIZEOF_ADDR_IFREQ(*ifr);
|
||||
|
||||
if ((strncmp(ifr->ifr_name, "shaper", 6) == 0)
|
||||
!= shaper) continue;
|
||||
|
||||
if (strncmp(ifr->ifr_name, "lo", 2) == 0)
|
||||
continue;
|
||||
if (strchr(ifr->ifr_name, ':') != NULL)
|
||||
continue;
|
||||
|
||||
/* Read interface flags */
|
||||
if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0) {
|
||||
fprintf(stderr, "ifdown: shutdown ");
|
||||
perror(ifr->ifr_name);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Expected in <net/if.h> according to
|
||||
* "UNIX Network Programming".
|
||||
*/
|
||||
#ifdef ifr_flagshigh
|
||||
flags = (ifr->ifr_flags & 0xffff) |
|
||||
(ifr->ifr_flagshigh << 16);
|
||||
#else
|
||||
flags = ifr->ifr_flags;
|
||||
#endif
|
||||
if (flags & IFF_UP) {
|
||||
flags &= ~(IFF_UP);
|
||||
#ifdef ifr_flagshigh
|
||||
ifr->ifr_flags = flags & 0xffff;
|
||||
ifr->ifr_flagshigh = flags >> 16;
|
||||
#else
|
||||
ifr->ifr_flags = flags;
|
||||
#endif
|
||||
if (ioctl(fd, SIOCSIFFLAGS, ifr) < 0) {
|
||||
fprintf(stderr, "ifdown: shutdown ");
|
||||
perror(ifr->ifr_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
#define WAIT_BETWEEN_SIGNALS 3 /* default time to wait between TERM and KILL */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* from dowall.c */
|
||||
void wall(const char *text, int remote);
|
||||
|
||||
#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;
|
||||
extern int wrote_wtmp_rlevel;
|
||||
extern int wrote_utmp_rlevel;
|
||||
extern char thislevel;
|
||||
extern char prevlevel;
|
||||
|
||||
/* 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
|
||||
#define D_WROTE_WTMP_RLEVEL -16
|
||||
#define D_WROTE_UTMP_RLEVEL -17
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#define UTMP_FILE "/var/run/utmp"
|
||||
#define RUN_LVL 1
|
||||
struct utmp
|
||||
{
|
||||
char ut_id[4];
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* initreq.h Interface to talk to init through /run/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>
|
||||
|
||||
#ifndef INIT_FIFO
|
||||
#define INIT_FIFO "/run/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
|
||||
|
||||
#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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,970 @@
|
|||
/*
|
||||
* 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 <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <utmp.h>
|
||||
#include <errno.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
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 2048
|
||||
#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 allow_long_username = 0; /* Show usernames longer than 8 characters */
|
||||
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 name_len = 8; /* Default print 8 characters of name */
|
||||
int domain_len = 16; /* Default print 16 characters of domain */
|
||||
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[PATH_MAX + 5]; /* max path + btmp + null terminator */
|
||||
char *p;
|
||||
|
||||
memset(btmp, '\0', PATH_MAX + 5);
|
||||
strncpy(btmp, WTMP_FILE, PATH_MAX);
|
||||
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;
|
||||
int mapped = 0;
|
||||
|
||||
flags = useip ? NI_NUMERICHOST : 0;
|
||||
|
||||
/*
|
||||
* IPv4 or IPv6 ?
|
||||
* 1. If last 3 4bytes are 0, must be IPv4
|
||||
* 2. If IPv6 in IPv4, handle as IPv4
|
||||
* 3. Anything else is IPv6
|
||||
*
|
||||
* Ugly.
|
||||
*/
|
||||
if (a[0] == 0 && a[1] == 0 && a[2] == (int32_t)htonl (0xffff))
|
||||
mapped = 1;
|
||||
|
||||
if (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[512];
|
||||
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;
|
||||
strncpy(logintime, ctime(&tmp), sizeof(logintime));
|
||||
logintime[sizeof(logintime)-1] = 0; /* enforce null termination */
|
||||
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 >= (int)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
|
||||
#define str(s) # s
|
||||
#define xstr(s) str(s)
|
||||
if (!altlist) {
|
||||
if (allow_long_username)
|
||||
{
|
||||
len = snprintf(final, sizeof(final),
|
||||
oldfmt ? "%-" xstr(OLD_NAMESIZE) "." xstr(OLD_NAMESIZE) "s %-12.12s "
|
||||
"%-16.16s %-16.16s %-7.7s %-12.12s\n"
|
||||
: "%-" xstr(UT_NAMESIZE) "." xstr(UT_NAMESIZE) "s %-12.12s "
|
||||
"%-16.16s %-16.16s %-7.7s %-12.12s\n",
|
||||
p->ut_name, utline,
|
||||
domain, logintime, logouttime, length);
|
||||
}
|
||||
else /* show short username */
|
||||
{
|
||||
len = snprintf(final, sizeof(final),
|
||||
fulltime ?
|
||||
"%-8.*s %-12.12s %-16.*s %-24.24s %-26.26s %-12.12s\n" :
|
||||
"%-8.*s %-12.12s %-16.*s %-16.16s %-7.7s %-12.12s\n",
|
||||
name_len, p->ut_name, utline,
|
||||
domain_len, domain, logintime, logouttime, length);
|
||||
} /* show short username */
|
||||
} else {
|
||||
if (allow_long_username)
|
||||
{
|
||||
len = snprintf(final, sizeof(final),
|
||||
oldfmt ? "%-" xstr(OLD_NAMESIZE) "." xstr(OLD_NAMESIZE) "s %-12.12s "
|
||||
"%-16.16s %-7.7s %-16.16s %s\n"
|
||||
: "%-" xstr(UT_NAMESIZE) "." xstr(UT_NAMESIZE) "s %-12.12s "
|
||||
"%-16.16s %-7.7s %-16.16s %s\n",
|
||||
p->ut_name, utline,
|
||||
logintime, logouttime, length, domain);
|
||||
}
|
||||
else /* show short username */
|
||||
{
|
||||
len = snprintf(final, sizeof(final),
|
||||
fulltime ?
|
||||
"%-8.*s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
|
||||
"%-8.*s %-12.12s %-16.16s %-7.7s %-12.12s %s\n",
|
||||
name_len, p->ut_name, utline,
|
||||
logintime, logouttime, length, domain);
|
||||
} /* done showing short username */
|
||||
}
|
||||
} else
|
||||
if (allow_long_username)
|
||||
{
|
||||
len = snprintf(final, sizeof(final),
|
||||
oldfmt ? "%-" xstr(OLD_NAMESIZE) "." xstr(OLD_NAMESIZE) "s %-12.12s "
|
||||
"%-16.16s %-7.7s %-12.12s\n"
|
||||
: "%-" xstr(UT_NAMESIZE) "." xstr(UT_NAMESIZE) "s %-12.12s "
|
||||
"%-16.16s %-7.7s %-12.12s\n",
|
||||
p->ut_name, utline,
|
||||
logintime, logouttime, length);
|
||||
}
|
||||
else /* show short username */
|
||||
{
|
||||
len = snprintf(final, sizeof(final),
|
||||
fulltime ?
|
||||
"%-8.*s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
|
||||
"%-8.*s %-12.12s %-16.16s %-7.7s %-12.12s\n",
|
||||
name_len, p->ut_name, utline,
|
||||
logintime, logouttime, length);
|
||||
} /* end of showing short username */
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
# if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)
|
||||
final[sizeof(final)-1] = '\0';
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Print out "final" string safely.
|
||||
*/
|
||||
for (s = final; *s; s++) {
|
||||
if (*s == '\n' || (*s >= 32 && (unsigned char)*s <= 126))
|
||||
putchar(*s);
|
||||
else
|
||||
putchar('*');
|
||||
}
|
||||
|
||||
if (len < 0 || (size_t)len >= sizeof(final))
|
||||
putchar('\n');
|
||||
|
||||
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] [-adioxFw] [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:RxadFliot:0123456789w")) != 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 'l':
|
||||
allow_long_username = 1;
|
||||
break;
|
||||
case 't':
|
||||
if ((until = parsetm(optarg)) == (time_t)-1) {
|
||||
fprintf(stderr, "%s: Invalid time value \"%s\"\n",
|
||||
progname, optarg);
|
||||
usage(progname);
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
if (UT_NAMESIZE > name_len)
|
||||
name_len = UT_NAMESIZE;
|
||||
if (UT_HOSTSIZE > domain_len)
|
||||
domain_len = UT_HOSTSIZE;
|
||||
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) {
|
||||
strncpy(ut.ut_line, "system down", OLD_LINESIZE - 1);
|
||||
quit = list(&ut, lastboot, R_NORMAL);
|
||||
}
|
||||
lastdown = lastrch = ut.ut_time;
|
||||
down = 1;
|
||||
break;
|
||||
case OLD_TIME:
|
||||
case NEW_TIME:
|
||||
if (extended) {
|
||||
strncpy(ut.ut_line,
|
||||
ut.ut_type == NEW_TIME ? "new time" :
|
||||
"old time", OLD_LINESIZE - 1);
|
||||
quit = list(&ut, lastdown, R_TIMECHANGE);
|
||||
}
|
||||
break;
|
||||
case BOOT_TIME:
|
||||
strncpy(ut.ut_line, "system boot", OLD_LINESIZE - 1);
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* logsave.c --- A program which saves the output of a program until
|
||||
* /var/log is mounted.
|
||||
*
|
||||
* Copyright (C) 2003 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
|
||||
#endif
|
||||
#ifndef HAVE_SIGNAL_H
|
||||
#define HAVE_SIGNAL_H
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#else
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
#endif
|
||||
|
||||
static int outfd = -1;
|
||||
static int outbufsize = 0;
|
||||
static void *outbuf = 0;
|
||||
static int verbose = 0;
|
||||
static int do_skip = 0;
|
||||
static int skip_mode = 0;
|
||||
static pid_t child_pid = -1;
|
||||
|
||||
static void usage(char *progname)
|
||||
{
|
||||
printf("Usage: %s [-asv] logfile program\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define SEND_LOG 0x01
|
||||
#define SEND_CONSOLE 0x02
|
||||
#define SEND_BOTH 0x03
|
||||
|
||||
/*
|
||||
* Helper function that does the right thing if write returns a
|
||||
* partial write, or an EAGAIN/EINTR error.
|
||||
*/
|
||||
static int write_all(int fd, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t ret;
|
||||
int c = 0;
|
||||
|
||||
while (count > 0) {
|
||||
ret = write(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
if ((errno == EAGAIN) || (errno == EINTR))
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
count -= ret;
|
||||
buf += ret;
|
||||
c += ret;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void send_output(const char *buffer, int c, int flag)
|
||||
{
|
||||
const char *cp;
|
||||
char *n;
|
||||
int cnt, d, del;
|
||||
|
||||
if (c == 0)
|
||||
c = strlen(buffer);
|
||||
|
||||
if (flag & SEND_CONSOLE) {
|
||||
cnt = c;
|
||||
cp = buffer;
|
||||
while (cnt) {
|
||||
del = 0;
|
||||
for (d=0; d < cnt; d++) {
|
||||
if (skip_mode &&
|
||||
(cp[d] == '\001' || cp[d] == '\002')) {
|
||||
del = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_all(1, cp, d);
|
||||
if (del)
|
||||
d++;
|
||||
cnt -= d;
|
||||
cp += d;
|
||||
}
|
||||
}
|
||||
if (!(flag & SEND_LOG))
|
||||
return;
|
||||
if (outfd > 0)
|
||||
write_all(outfd, buffer, c);
|
||||
else {
|
||||
n = realloc(outbuf, outbufsize + c);
|
||||
if (n) {
|
||||
outbuf = n;
|
||||
memcpy(((char *)outbuf)+outbufsize, buffer, c);
|
||||
outbufsize += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int do_read(int fd)
|
||||
{
|
||||
int c;
|
||||
char buffer[4096], *cp, *sep;
|
||||
|
||||
c = read(fd, buffer, sizeof(buffer)-1);
|
||||
if (c <= 0)
|
||||
return c;
|
||||
if (do_skip) {
|
||||
send_output(buffer, c, SEND_CONSOLE);
|
||||
buffer[c] = 0;
|
||||
cp = buffer;
|
||||
while (*cp) {
|
||||
if (skip_mode) {
|
||||
cp = strchr(cp, '\002');
|
||||
if (!cp)
|
||||
return 0;
|
||||
cp++;
|
||||
skip_mode = 0;
|
||||
continue;
|
||||
}
|
||||
sep = strchr(cp, '\001');
|
||||
if (sep)
|
||||
*sep = 0;
|
||||
send_output(cp, 0, SEND_LOG);
|
||||
if (sep) {
|
||||
cp = sep + 1;
|
||||
skip_mode = 1;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
} else
|
||||
send_output(buffer, c, SEND_BOTH);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void signal_term(int sig)
|
||||
{
|
||||
if (child_pid > 0)
|
||||
kill(child_pid, sig);
|
||||
}
|
||||
|
||||
static int run_program(char **argv)
|
||||
{
|
||||
int fds[2];
|
||||
int status, rc, pid;
|
||||
char buffer[80];
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
struct sigaction sa;
|
||||
#endif
|
||||
|
||||
if (pipe(fds) < 0) {
|
||||
perror("pipe");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sa.sa_handler = signal_term;
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
sigaction(SIGTERM, &sa, 0);
|
||||
#ifdef SA_RESTART
|
||||
sa.sa_flags = SA_RESTART;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("vfork");
|
||||
exit(1);
|
||||
}
|
||||
if (pid == 0) {
|
||||
dup2(fds[1],1); /* fds[1] replaces stdout */
|
||||
dup2(fds[1],2); /* fds[1] replaces stderr */
|
||||
close(fds[0]); /* don't need this here */
|
||||
close(fds[1]);
|
||||
|
||||
execvp(argv[0], argv);
|
||||
perror(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
child_pid = pid;
|
||||
close(fds[1]);
|
||||
|
||||
while (!(waitpid(pid, &status, WNOHANG ))) {
|
||||
do_read(fds[0]);
|
||||
}
|
||||
child_pid = -1;
|
||||
do_read(fds[0]);
|
||||
close(fds[0]);
|
||||
|
||||
if ( WIFEXITED(status) ) {
|
||||
rc = WEXITSTATUS(status);
|
||||
if (rc) {
|
||||
send_output(argv[0], 0, SEND_BOTH);
|
||||
sprintf(buffer, " exited with status code %d\n", rc);
|
||||
send_output(buffer, 0, SEND_BOTH);
|
||||
}
|
||||
} else {
|
||||
if (WIFSIGNALED(status)) {
|
||||
send_output(argv[0], 0, SEND_BOTH);
|
||||
sprintf(buffer, "died with signal %d\n",
|
||||
WTERMSIG(status));
|
||||
send_output(buffer, 0, SEND_BOTH);
|
||||
return 1;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int copy_from_stdin(void)
|
||||
{
|
||||
int c, bad_read = 0;
|
||||
|
||||
while (1) {
|
||||
c = do_read(0);
|
||||
if ((c == 0 ) ||
|
||||
((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) {
|
||||
if (bad_read++ > 3)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (c < 0) {
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
bad_read = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, pid, rc;
|
||||
char *outfn, **cpp;
|
||||
int openflags = O_CREAT|O_WRONLY|O_TRUNC;
|
||||
int send_flag = SEND_LOG;
|
||||
int do_stdin;
|
||||
time_t t;
|
||||
|
||||
while ((c = getopt(argc, argv, "+asv")) != EOF) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
openflags &= ~O_TRUNC;
|
||||
openflags |= O_APPEND;
|
||||
break;
|
||||
case 's':
|
||||
do_skip = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
send_flag |= SEND_CONSOLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind == argc || optind+1 == argc)
|
||||
usage(argv[0]);
|
||||
outfn = argv[optind];
|
||||
optind++;
|
||||
argv += optind;
|
||||
/* argc -= optind; - this is not used */
|
||||
|
||||
outfd = open(outfn, openflags, 0644);
|
||||
do_stdin = !strcmp(argv[0], "-");
|
||||
|
||||
send_output("Log of ", 0, send_flag);
|
||||
if (do_stdin)
|
||||
send_output("stdin", 0, send_flag);
|
||||
else {
|
||||
for (cpp = argv; *cpp; cpp++) {
|
||||
send_output(*cpp, 0, send_flag);
|
||||
send_output(" ", 0, send_flag);
|
||||
}
|
||||
}
|
||||
send_output("\n", 0, send_flag);
|
||||
t = time(0);
|
||||
send_output(ctime(&t), 0, send_flag);
|
||||
send_output("\n", 0, send_flag);
|
||||
|
||||
if (do_stdin)
|
||||
rc = copy_from_stdin();
|
||||
else
|
||||
rc = run_program(argv);
|
||||
|
||||
send_output("\n", 0, send_flag);
|
||||
t = time(0);
|
||||
send_output(ctime(&t), 0, send_flag);
|
||||
send_output("----------------\n", 0, send_flag);
|
||||
|
||||
if (outbuf) {
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
if (pid) {
|
||||
if (verbose)
|
||||
printf("Backgrounding to save %s later\n",
|
||||
outfn);
|
||||
exit(rc);
|
||||
}
|
||||
setsid(); /* To avoid getting killed by init */
|
||||
while (outfd < 0) {
|
||||
outfd = open(outfn, openflags, 0644);
|
||||
sleep(1);
|
||||
}
|
||||
write_all(outfd, outbuf, outbufsize);
|
||||
free(outbuf);
|
||||
}
|
||||
if (outfd >= 0)
|
||||
close(outfd);
|
||||
|
||||
exit(rc);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 2048
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function checks to see if the passed path is listed in the
|
||||
/proc/mounts file. If /proc/mounts does not exist or cannot
|
||||
be read, we return false. If the path is not found, we return false.
|
||||
If the path is found we return true.
|
||||
*/
|
||||
int do_proc_check(char *path)
|
||||
{
|
||||
FILE *mounts;
|
||||
char *found = NULL, *status;
|
||||
char *target_string;
|
||||
char line[512];
|
||||
int last_character;
|
||||
|
||||
target_string = (char *) calloc( strlen(path) + 3, sizeof(char));
|
||||
if (! target_string)
|
||||
return 0;
|
||||
|
||||
mounts = fopen("/proc/mounts", "r");
|
||||
if (! mounts)
|
||||
{
|
||||
free(target_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy path so we can adjust it without harming the original */
|
||||
sprintf(target_string, "%s", path);
|
||||
/* trim trailing slash */
|
||||
last_character = strlen(target_string) - 1;
|
||||
if ( (last_character >= 1) && (target_string[last_character] == '/') )
|
||||
target_string[last_character] = '\0';
|
||||
|
||||
/* Search for path name in /proc/mounts file */
|
||||
status = fgets(line, 512, mounts);
|
||||
while ( (status) && (! found) )
|
||||
{
|
||||
found = strstr(line, target_string);
|
||||
if (! found)
|
||||
status = fgets(line, 512, mounts);
|
||||
}
|
||||
fclose(mounts);
|
||||
free(target_string);
|
||||
return found ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void usage(void) {
|
||||
fprintf(stderr, "Usage: mountpoint [-p] [-q] [-d] [-x] path\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct stat st, st2;
|
||||
char buf[PATH_MAX + 1];
|
||||
char *path;
|
||||
int quiet = 0;
|
||||
int showdev = 0;
|
||||
int xdev = 0;
|
||||
int c, r;
|
||||
int check_proc = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "dpqx")) != EOF) switch(c) {
|
||||
case 'd':
|
||||
showdev = 1;
|
||||
break;
|
||||
case 'p':
|
||||
check_proc = 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);
|
||||
strncat(buf, "/..", 3);
|
||||
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) ) ;
|
||||
|
||||
(A || (!A && B)) is the same as (A || B) so simplifying this below.
|
||||
Thanks to David Binderman for pointing this out. -- Jesse
|
||||
*/
|
||||
r = ( (st.st_dev != st2.st_dev) || (st.st_ino == st2.st_ino) );
|
||||
|
||||
/* Mount point was not found yet. If we have access
|
||||
to /proc we can check there too. */
|
||||
if ( (!r) && (check_proc) )
|
||||
{
|
||||
if ( do_proc_check(path) )
|
||||
r = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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_OLD "/etc/powerstatus" /* COMPAT: SIGPWR reason (OK/BAD) */
|
||||
#define PWRSTAT "/var/run/powerstatus" /* COMPAT: SIGPWR reason (OK/BAD) */
|
||||
#define RUNLEVEL_LOG "/var/run/runlevel" /* neutral place to store run level */
|
||||
|
||||
#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
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "bootlogd.h"
|
||||
|
||||
#ifndef MAX_LINE
|
||||
#define MAX_LINE 256
|
||||
#endif
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
printf("readbootlog reads the system's boot log, stripping away\n");
|
||||
printf("control characters to make the log human readable.\n\n");
|
||||
printf("Usage for readbootlog: readbootlog [-h] [-f logfile]\n");
|
||||
printf("\t\t-h display this help message\n");
|
||||
printf("\t\t-f <logfile> display a specific boot log file\n");
|
||||
printf("\t\t default is to use %s\n", LOGFILE);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
Clean up the unwanted characters from a line of input.
|
||||
Cleaned line is passed back in output_line.
|
||||
Returns TRUE on success or FALSE if we encounter an error.
|
||||
*/
|
||||
int Clean_Line(char *source_line, char *output_line)
|
||||
{
|
||||
int source_index = 0, target_index = 0;
|
||||
int source_max_index;
|
||||
char a_letter;
|
||||
int done;
|
||||
char *garbage;
|
||||
|
||||
if (! source_line) return FALSE;
|
||||
if (! output_line) return FALSE;
|
||||
|
||||
source_max_index = strlen(source_line);
|
||||
while (source_index < source_max_index)
|
||||
{
|
||||
a_letter = source_line[source_index];
|
||||
if (a_letter == '^')
|
||||
{
|
||||
/* skip ahead until we find a valid place to stop */
|
||||
done = FALSE;
|
||||
while (! done)
|
||||
{
|
||||
source_index++;
|
||||
if (source_index >= source_max_index)
|
||||
done = TRUE;
|
||||
else
|
||||
{
|
||||
a_letter = source_line[source_index];
|
||||
if ( (a_letter == '.') || (a_letter == ' ') ||
|
||||
(a_letter == '(') || (a_letter == 'd') ||
|
||||
(a_letter == '\n') )
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
} /* done found character to scrub */
|
||||
else if ( (a_letter == '?') && (source_line[source_index + 1] == '?') &&
|
||||
(source_line[source_index + 2] == '7') )
|
||||
{
|
||||
source_index += 3;
|
||||
output_line[target_index] = ' ';
|
||||
target_index++;
|
||||
}
|
||||
else if ( (a_letter == '8') && (source_line[source_index + 1] == '?') &&
|
||||
(source_line[source_index + 2] == '?') )
|
||||
{
|
||||
source_index += 3;
|
||||
output_line[target_index] = ']';
|
||||
target_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_line[target_index] = a_letter;
|
||||
target_index++;
|
||||
source_index++;
|
||||
} /* found valid character */
|
||||
} /* done processing line */
|
||||
|
||||
garbage = strstr(output_line, " .\n");
|
||||
if (garbage)
|
||||
{
|
||||
garbage[0] = '\n';
|
||||
garbage[1] = '\0';
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *log_file = NULL;
|
||||
char *log_filename = LOGFILE;
|
||||
char line[MAX_LINE];
|
||||
char output[MAX_LINE];
|
||||
char *status;
|
||||
int c;
|
||||
|
||||
/* check provided options */
|
||||
while ( (c = getopt(argc, argv, "hf:") ) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(0);
|
||||
case 'f':
|
||||
log_filename = optarg;
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
} /* done processing arguments */
|
||||
|
||||
log_file = fopen(log_filename, "r");
|
||||
if (log_file)
|
||||
{
|
||||
status = fgets(line, MAX_LINE, log_file);
|
||||
while (status)
|
||||
{
|
||||
memset(output, '\0', MAX_LINE);
|
||||
if ( Clean_Line(line, output) )
|
||||
{
|
||||
printf("%s", output);
|
||||
}
|
||||
status = fgets(line, MAX_LINE, log_file);
|
||||
} /* done reading file lines */
|
||||
fclose(log_file);
|
||||
} /* end of successfully opened log file */
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unable to open file %s\n", log_filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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>
|
||||
#include "runlevellog.h"
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct utmp *ut;
|
||||
char prev;
|
||||
int status, runlevel;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
endutent();
|
||||
|
||||
status = Read_Runlevel_Log(&runlevel);
|
||||
if (status)
|
||||
{
|
||||
printf("N %c\n", runlevel);
|
||||
return 0;
|
||||
}
|
||||
printf("unknown\n");
|
||||
return(1);
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* runlevellog - Saves and restores runlevel from distor-neutral location.
|
||||
*
|
||||
*
|
||||
* This file is part of the sysvinit suite,
|
||||
* Copyright (C) 2018 Jesse Smith
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 "paths.h"
|
||||
#include "runlevellog.h"
|
||||
|
||||
/*
|
||||
Write the current runlevel to its log file.
|
||||
The function returns TRUE on success and FALSE
|
||||
on failure.
|
||||
*/
|
||||
int Write_Runlevel_Log(int new_runlevel)
|
||||
{
|
||||
FILE *log_file;
|
||||
int status;
|
||||
|
||||
log_file = fopen(RUNLEVEL_LOG, "w");
|
||||
if (! log_file)
|
||||
return FALSE;
|
||||
|
||||
status = fprintf(log_file, "%c", new_runlevel);
|
||||
fclose(log_file);
|
||||
if (status < 1)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function reads the last runlevel from the log file.
|
||||
The function stores the read value at the addressed passed
|
||||
into the function (aka runlevel). The function returns
|
||||
TRUE on success and FALSE on failure.
|
||||
*/
|
||||
int Read_Runlevel_Log(int *runlevel)
|
||||
{
|
||||
FILE *log_file;
|
||||
int status;
|
||||
|
||||
log_file = fopen(RUNLEVEL_LOG, "r");
|
||||
if (! log_file)
|
||||
return FALSE;
|
||||
|
||||
status = fscanf(log_file, "%c", (char *) runlevel);
|
||||
fclose(log_file);
|
||||
if (status < 1)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* runlevellog - Saves and restores runlevel from distor-neutral location.
|
||||
*
|
||||
*
|
||||
* This file is part of the sysvinit suite,
|
||||
* Copyright (C) 2018 Jesse Smith
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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 RUNLEVEL_LOG_HEADER__
|
||||
#define RUNLEVEL_LOG_HEADER__
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
int Write_Runlevel_Log(int new_runlevel);
|
||||
int Read_Runlevel_Log(int *runlevel);
|
||||
|
||||
#endif
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,836 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE /* otherwise `extern char **environ' is missed */
|
||||
#endif
|
||||
#ifndef ACCTON_OFF
|
||||
# define ACCTON_OFF 0
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysmacros.h> /* brought in my LFS patch */
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
#include <syslog.h>
|
||||
#include "paths.h"
|
||||
#include "reboot.h"
|
||||
#include "initreq.h"
|
||||
#include "init.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#define MESSAGELEN 256
|
||||
#define STATELEN 64
|
||||
#define WHEN_SIZE 64
|
||||
|
||||
/* Whether we should warn system is shutting down */
|
||||
#define QUIET_FULL 2
|
||||
#define QUIET_PARTIAL 1
|
||||
#define QUIET_NONE 0
|
||||
|
||||
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[STATELEN]; /* What are we gonna do */
|
||||
int doself = 0; /* Don't use init */
|
||||
int got_alrm = 0;
|
||||
|
||||
char *clean_env[] = {
|
||||
"HOME=/",
|
||||
"PATH=" PATH_DEFAULT,
|
||||
"TERM=dumb",
|
||||
"SHELL=/bin/sh",
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
# ifdef __GNUC__
|
||||
void stopit(int sig __attribute__((unused)))
|
||||
# else
|
||||
void stopit(int sig)
|
||||
# endif
|
||||
|
||||
{
|
||||
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 [-akrhPHfFnc] [-t sec] 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 can only be used along with -h flag.\n"
|
||||
"\t\t -H: halt action is to just halt.\n"
|
||||
"\t\t can only be used along with -h flag.\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 -q: quiet mode - display fewer shutdown warnings.\n"
|
||||
"\t\t -Q: full quiet mode - display only final shutdown warning.\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;
|
||||
size_t 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 >= (int)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 /run/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) {
|
||||
ssize_t p = 0;
|
||||
size_t s = sizeof(request);
|
||||
void *ptr = &request;
|
||||
while (s > 0) {
|
||||
p = write(fd, ptr, s);
|
||||
if (p < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
ptr += p;
|
||||
s -= p;
|
||||
}
|
||||
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 issue_warn(int mins)
|
||||
{
|
||||
char buf[MESSAGELEN + sizeof(newstate) + 1];
|
||||
int len;
|
||||
|
||||
buf[0] = 0;
|
||||
strncpy(buf, message, MESSAGELEN);
|
||||
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, 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);
|
||||
|
||||
if (chdir("/"))
|
||||
exit(1);
|
||||
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: %s.\r\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Kill all processes. */
|
||||
fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
|
||||
kill(-1, SIGTERM);
|
||||
sleep(sltime ? atoi(sltime) : WAIT_BETWEEN_SIGNALS);
|
||||
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. */
|
||||
/* Give init the chance to collect zombies. */
|
||||
/* sleep(1); */
|
||||
|
||||
/* Record the fact that we're going down */
|
||||
write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
|
||||
|
||||
/* This is for those who have quota installed. */
|
||||
#if defined(ACCTON_OFF)
|
||||
# if (ACCTON_OFF > 1) && (_BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500))
|
||||
/* This is an alternative way to disable accounting, saving a fork() */
|
||||
if (acct(NULL))
|
||||
fprintf(stderr, "shutdown: can not stop process accounting: %s.\r\n", strerror(errno));
|
||||
# elif (ACCTON_OFF > 0)
|
||||
spawn(1, "accton", "off", NULL);
|
||||
# else
|
||||
spawn(1, "accton", NULL);
|
||||
# endif
|
||||
#endif
|
||||
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 issue_shutdown(char *halttype)
|
||||
{
|
||||
char *args[8];
|
||||
int argp = 0;
|
||||
int do_halt = (down_level[0] == '0');
|
||||
|
||||
/* Warn for the last time */
|
||||
issue_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 quiet_mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (quiet_mode == QUIET_FULL) return FALSE;
|
||||
else if (quiet_mode == QUIET_PARTIAL)
|
||||
{
|
||||
if (wt == 10)
|
||||
return TRUE;
|
||||
else if (wt == 5)
|
||||
return TRUE;
|
||||
else if ( (wt % 60) == 0)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
/* no silence setting, print lots of warnings */
|
||||
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, target_time;
|
||||
char *halttype;
|
||||
char *downusers[32];
|
||||
char buf[128];
|
||||
char term[UT_LINESIZE + 6];
|
||||
char *sp;
|
||||
char when[WHEN_SIZE];
|
||||
int c, i, wt;
|
||||
int hours, mins;
|
||||
int didnolog = 0;
|
||||
int cancel = 0;
|
||||
int useacl = 0;
|
||||
int pid = 0;
|
||||
int user_ok = 0;
|
||||
int quiet_level = QUIET_NONE; /* Whether to display shutdown warning */
|
||||
|
||||
/* We can be installed setuid root (executable for a special group) */
|
||||
/*
|
||||
This way is risky, do error check on setuid call.
|
||||
setuid(geteuid());
|
||||
*/
|
||||
errno = 0;
|
||||
if (setuid(geteuid()) == -1) {
|
||||
fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr, "shutdown: you must be root to do that!\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
strcpy(down_level, "1");
|
||||
halttype = NULL;
|
||||
memset(when, '\0', WHEN_SIZE);
|
||||
|
||||
/* Process the options. */
|
||||
while((c = getopt(argc, argv, "HPacqQkrhnfFyt:g:i:")) != EOF) {
|
||||
switch(c) {
|
||||
case 'H':
|
||||
halttype = "HALT";
|
||||
break;
|
||||
case 'P':
|
||||
halttype = "POWEROFF";
|
||||
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 'q': /* put into somewhat quiet mode */
|
||||
quiet_level = QUIET_PARTIAL;
|
||||
break;
|
||||
case 'Q': /* put into full quiet mode */
|
||||
quiet_level = QUIET_FULL;
|
||||
break;
|
||||
case 'y': /* Ignored for sysV compatibility */
|
||||
break;
|
||||
case 'g': /* sysv style to specify time. */
|
||||
strncpy(when, optarg, WHEN_SIZE - 1);
|
||||
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) {
|
||||
if (fscanf(fp, "%d", &pid) != 1)
|
||||
pid = 0;
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* Read remaining words, skip time if needed. */
|
||||
message[0] = 0;
|
||||
for(c = optind + (!cancel && !when[0]); 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, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Check syntax. */
|
||||
if (when[0] == '\0') {
|
||||
if (optind == argc) usage();
|
||||
strncpy(when, argv[optind++], WHEN_SIZE - 1);
|
||||
}
|
||||
|
||||
/* 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':
|
||||
strncpy(newstate, "for system halt", STATELEN);
|
||||
break;
|
||||
case '6':
|
||||
strncpy(newstate, "for reboot", STATELEN);
|
||||
break;
|
||||
case '1':
|
||||
strncpy(newstate, "to maintenance mode", STATELEN);
|
||||
break;
|
||||
default:
|
||||
snprintf(newstate, STATELEN, "to runlevel %s", down_level);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go to the root directory */
|
||||
if (chdir("/")) {
|
||||
fprintf(stderr, "shutdown: chdir(/): %m\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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");
|
||||
|
||||
sp = when;
|
||||
if (when[0] == '+') sp++;
|
||||
/* Decode shutdown time. */
|
||||
for ( ; *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) issue_shutdown(halttype);
|
||||
|
||||
/* Rather than loop and reduce wt (wait time) once per minute,
|
||||
we shall check the current time against the target time.
|
||||
Then calculate the remaining wating time based on the difference
|
||||
between current time and target time.
|
||||
This avoids missing shutdown time (target time) after the
|
||||
computer has been asleep. -- Jesse
|
||||
*/
|
||||
/* target time, in seconds = current time + wait time */
|
||||
time(&t);
|
||||
target_time = t + (60 * wt);
|
||||
|
||||
/* Give warnings on regular intervals and finally shutdown. */
|
||||
if (wt < 15 && !needwarning(wt, quiet_level)) issue_warn(wt);
|
||||
while(wt) {
|
||||
if (wt <= 5 && !didnolog) {
|
||||
donologin(wt);
|
||||
didnolog++;
|
||||
}
|
||||
if (needwarning(wt, quiet_level)) issue_warn(wt);
|
||||
hardsleep(60);
|
||||
time(&t); /* get current time once per minute */
|
||||
if (t >= target_time) /* past the target */
|
||||
wt = 0;
|
||||
else if ( (target_time - t) <= 60 ) /* less 1 min remains */
|
||||
{
|
||||
hardsleep(target_time - t);
|
||||
wt = 0;
|
||||
}
|
||||
else /* more than 1 min remains */
|
||||
wt = (int) (target_time - t) / 60;
|
||||
}
|
||||
issue_shutdown(halttype);
|
||||
|
||||
return 0; /* Never happens */
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* 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>
|
||||
#ifdef __FreeBSD__
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
|
||||
#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;
|
||||
|
||||
/*
|
||||
* Can't do much if WTMP_FILE is not present or not writable.
|
||||
*/
|
||||
if (access(WTMP_FILE, W_OK) < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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, "~");
|
||||
|
||||
/*
|
||||
* Note if we are going to write a runlevel record.
|
||||
*/
|
||||
if (type == RUN_LVL) wrote_wtmp_rlevel++;
|
||||
|
||||
/*
|
||||
* See if we need to write a runlevel 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 runlevel record.
|
||||
*/
|
||||
if (wrote_wtmp_rlevel == 0 && type != RUN_LVL) {
|
||||
int runlevel = thislevel;
|
||||
int oldlevel = prevlevel;
|
||||
write_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
|
||||
}
|
||||
#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 or not writable.
|
||||
*/
|
||||
if (access(UTMP_FILE, W_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 UTMP we write a delayed boot record.
|
||||
*/
|
||||
if (wrote_utmp_reboot == 0 && type != BOOT_TIME)
|
||||
write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL);
|
||||
|
||||
/*
|
||||
* Note if we are going to write a runlevel record.
|
||||
*/
|
||||
if (type == RUN_LVL) wrote_utmp_rlevel++;
|
||||
|
||||
/*
|
||||
* See if we need to write a runlevel 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 UTMP we write a delayed runlevel record.
|
||||
*/
|
||||
if (wrote_utmp_rlevel == 0 && type != RUN_LVL) {
|
||||
int runlevel = thislevel;
|
||||
int oldlevel = prevlevel;
|
||||
write_utmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~", 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* 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_buf[INET6_ADDRSTRLEN+1];
|
||||
const char *addr_string, *time_string;
|
||||
void *in_addr = &ut.ut_addr_v6;
|
||||
size_t addr_length = INET6_ADDRSTRLEN;
|
||||
int addr_family = AF_INET6;
|
||||
|
||||
if (!ut.ut_addr_v6[1] && !ut.ut_addr_v6[2] && !ut.ut_addr_v6[3]) {
|
||||
addr_family = AF_INET;
|
||||
addr_length = INET_ADDRSTRLEN;
|
||||
in_addr = &ut.ut_addr;
|
||||
}
|
||||
if ((addr_string = inet_ntop(addr_family, in_addr, addr_buf, addr_length)) == 0) {
|
||||
addr_buf[0] = '\0';
|
||||
addr_string = &addr_buf[0];
|
||||
}
|
||||
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
|
||||
# ifdef __GNUC__
|
||||
undump(FILE *fp, int forever __attribute__((unused)), int oldfmt)
|
||||
#else
|
||||
undump(FILE *fp, int forever, int oldfmt)
|
||||
#endif
|
||||
{
|
||||
struct utmp ut;
|
||||
struct oldutmp uto;
|
||||
char s_addr[16], s_time[29], *linestart;
|
||||
|
||||
linestart = malloc(1024 * sizeof *linestart);
|
||||
s_addr[15] = 0;
|
||||
s_time[28] = 0;
|
||||
|
||||
while(fgets(linestart, 1023, fp))
|
||||
{
|
||||
char *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);
|
||||
(void)line; /* Quiet down static source analyzers */
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -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>
|
||||
#include <sys/types.h>
|
||||
#include "init.h"
|
||||
|
||||
|
||||
#define MAXLEN 4096
|
||||
#define LINE_SIZE 80
|
||||
#define MAXLINES 20
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[MAXLEN];
|
||||
char line[LINE_SIZE + 3]; /* leave room for \r\n\0 */
|
||||
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-4) 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 (%zu chars)",
|
||||
whoami, i, strlen(buf));
|
||||
closelog();
|
||||
|
||||
unsetenv("TZ");
|
||||
wall(buf, remote);
|
||||
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue