Drop hurd specific dependency on libc0.3 (>= 2.3.2.ds1-12). It is

no longer needed according to Michael Bunk.  Patch from Michael
Biebl.
This commit is contained in:
Petter Reinholdtsen 2009-09-10 08:28:49 +00:00
commit 2fe47a3c9f
63 changed files with 13017 additions and 0 deletions

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

26
COPYRIGHT Normal file
View File

@ -0,0 +1,26 @@
Sysvinit is Copyright (C) 1991-2004 Miquel van Smoorenburg
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Send patches to sysvinit@savannah.nognu.org
The of the start-stop-daemon
* A rewrite of the original Debian's start-stop-daemon Perl script
* in C (faster - it is executed many times during system startup).
*
* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
* public domain.

7
README Normal file
View File

@ -0,0 +1,7 @@
contrib Unofficial stuff
doc Documentation, mostly obsolete
man Manual pages, not obsolete
obsolete Really obsolete stuff ;)
src Source code

16
contrib/TODO Normal file
View File

@ -0,0 +1,16 @@
There are several things on the wishlist. See also the "wishlist" bugs filed
against sysvinit in the debian bugs system (http://www.debian.org/Bugs/).
1. A special target for kbrequest, so that extra CHILDs are
created (each one needs its own utmp/wtmp bookkeeping)
2. Extend the initreq.h interface?
3. Add GNU last long options to last
4. Write all boot messages to a logfile
Problem: TIOCCONS ioctl redirects console output, it doesn't copy it.
I think this is not easily possible without kernel support.
I do not like the idea of booting with a pseudo tty as console and
a redirect process behind it writing to both the real console and a
logfile - too fragile.

29
contrib/alexander.viro Normal file
View File

@ -0,0 +1,29 @@
I proposed moving some stuff to a seperate file, such as the
re-exec routines. Alexander wrote:
According to Alexander Viro <viro@math.psu.edu>:
> As for the code separation - I think it's nice. Actually, read_inittab()
> with get_part() and newFamily are also pretty separatable. Another good
> set is any(), spawn(), startup(), spawn_emerg() and start_if_needed().
> BTW, fail_check();process_signals(); is equivalent to process_signal();
> fail_check();. I think that swapping them (in main loop) would be a good
> idea - then we can move fail_check() into start_if_needed(). And one more
> - I'ld propose to move start_if_needed to the beginning of the main loop,
> as in
> foo();
> while(1) { bar();foo();
> #if 0
> baz();
> #endif
> }
> to
> while(1) { foo();bar();
> #if 0
> baz();
> #endif
> }
>
>
> What do you think about it?

View File

@ -0,0 +1,45 @@
Start-stop-daemon is the program that is used by the DEBIAN style init
scripts to start and stop services. This program is part of the "dpkg"
package by Ian Jackson. However there is also a seperate C version (the
original is in perl) available written by Marek Michalkiewicz. I'm including
it for your convinience.
Note that the latest debian dpkg packages (4.0.18 and later) contain
a much improved update-rc.d. This code is almost a year old.
The original announcement follows:
From: Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>
Message-Id: <199606060324.FAA19493@i17linuxb.ists.pwr.wroc.pl>
Subject: Fast start-stop-daemon in C
To: debian-devel@lists.debian.org
Date: Thu, 6 Jun 1996 05:24:18 +0200 (MET DST)
Some time ago I wrote a faster C replacement for the start-stop-daemon
perl script. I use it for some time now (the most recent changes were
just a nicer help screen; the code is quite stable).
This makes the system boot faster (especially on low end machines),
and important system startup scripts no longer depend on another big
package (perl). Maybe in the future we can get to the point where
a minimal system will work without perl installed at all (packages
which need it in {pre,post}{inst,rm} scripts would depend on perl).
The only problem known so far to me is that I have to reinstall this
program after every dpkg upgrade which overwrites it with that nice
slooow perl script :-).
Just compile this program and drop the binary in /usr/sbin instead
of the original /usr/sbin/start-stop-daemon perl script (make a copy
of it first, just in case). See below for source code. I placed it
in the public domain, but if it has to be GPL-ed to be included in
dpkg, just tell me. Including it in dpkg would close Bug#1670.
I am posting it here so that it can be tested by more people than
just me. Bugs are unlikely though.
Have fun,
Marek

430
contrib/start-stop-daemon.c Normal file
View File

@ -0,0 +1,430 @@
/*
* A rewrite of the original Debian's start-stop-daemon Perl script
* in C (faster - it is executed many times during system startup).
*
* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
* public domain.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <getopt.h>
#include <pwd.h>
#define VERSION "version 0.3, 1996-06-05"
static int testmode = 0;
static int quietmode = 0;
static int exitnodo = 1;
static int start = 0;
static int stop = 0;
static int signal_nr = 15;
static int user_id = -1;
static const char *userspec = NULL;
static const char *cmdname = NULL;
static char *execname = NULL;
static char *startas = NULL;
static const char *pidfile = NULL;
static const char *progname = "";
static struct stat exec_stat;
struct pid_list {
struct pid_list *next;
int pid;
};
static struct pid_list *found = NULL;
static struct pid_list *killed = NULL;
static void *xmalloc(int size);
static void push(struct pid_list **list, int pid);
static void do_help(void);
static void parse_options(int argc, char * const *argv);
static int pid_is_exec(int pid, const struct stat *esb);
static int pid_is_user(int pid, int uid);
static int pid_is_cmd(int pid, const char *name);
static void check(int pid);
static void do_pidfile(const char *name);
static void do_procfs(void);
static void do_stop(void);
#ifdef __GNUC__
static void fatal(const char *format, ...)
__attribute__((noreturn, format(printf, 1, 2)));
static void badusage(const char *msg)
__attribute__((noreturn));
#else
static void fatal(const char *format, ...);
static void badusage(const char *msg);
#endif
static void
fatal(const char *format, ...)
{
va_list arglist;
fprintf(stderr, "%s: ", progname);
va_start(arglist, format);
vfprintf(stderr, format, arglist);
va_end(arglist);
putc('\n', stderr);
exit(2);
}
static void *
xmalloc(int size)
{
void *ptr;
ptr = malloc(size);
if (ptr)
return ptr;
fatal("malloc(%d) failed", size);
}
static void
push(struct pid_list **list, int pid)
{
struct pid_list *p;
p = xmalloc(sizeof(*p));
p->next = *list;
p->pid = pid;
*list = p;
}
static void
do_help(void)
{
printf("\
start-stop-daemon for Debian Linux - small and fast C version written by\n\
Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
VERSION "\n\
\n\
Usage:
start-stop-daemon -S|--start options ... -- arguments ...\n\
start-stop-daemon -K|--stop options ...\n\
start-stop-daemon -H|--help\n\
start-stop-daemon -V|--version\n\
\n\
Options (at least one of --exec|--pidfile|--user is required):
-x|--exec <executable> program to start/check if it is running\n\
-p|--pidfile <pid-file> pid file to check\n\
-u|--user <username>|<uid> stop this user's processes\n\
-n|--name <process-name> stop processes with this name\n\
-s|--signal <signal> signal to send (default 15)\n\
-a|--startas <pathname> program to start (default <executable>)\n\
-t|--test test mode, don't do anything\n\
-o|--oknodo exit status 0 (not 1) if nothing done\n\
-q|--quiet | -v, --verbose\n\
\n\
Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo) 2 = trouble\n");
}
static void
badusage(const char *msg)
{
if (msg && *msg)
fprintf(stderr, "%s: %s\n", progname, msg);
fprintf(stderr, "Try `%s --help' for more information.\n", progname);
exit(2);
}
static void
parse_options(int argc, char * const *argv)
{
static struct option longopts[] = {
{ "help", 0, NULL, 'H'},
{ "stop", 0, NULL, 'K'},
{ "start", 0, NULL, 'S'},
{ "version", 0, NULL, 'V'},
{ "startas", 1, NULL, 'a'},
{ "name", 1, NULL, 'n'},
{ "oknodo", 0, NULL, 'o'},
{ "pidfile", 1, NULL, 'p'},
{ "quiet", 0, NULL, 'q'},
{ "signal", 1, NULL, 's'},
{ "test", 0, NULL, 't'},
{ "user", 1, NULL, 'u'},
{ "verbose", 0, NULL, 'v'},
{ "exec", 1, NULL, 'x'},
{ NULL, 0, NULL, 0}
};
int c;
for (;;) {
c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:",
longopts, (int *) 0);
if (c == -1)
break;
switch (c) {
case 'H': /* --help */
do_help();
exit(0);
case 'K': /* --stop */
stop = 1;
break;
case 'S': /* --start */
start = 1;
break;
case 'V': /* --version */
printf("start-stop-daemon " VERSION "\n");
exit(0);
case 'a': /* --startas <pathname> */
startas = optarg;
break;
case 'n': /* --name <process-name> */
cmdname = optarg;
break;
case 'o': /* --oknodo */
exitnodo = 0;
break;
case 'p': /* --pidfile <pid-file> */
pidfile = optarg;
break;
case 'q': /* --quiet */
quietmode = 1;
break;
case 's': /* --signal <signal> */
if (sscanf(optarg, "%d", &signal_nr) != 1)
badusage("--signal takes a numeric argument");
break;
case 't': /* --test */
testmode = 1;
break;
case 'u': /* --user <username>|<uid> */
userspec = optarg;
break;
case 'v': /* --verbose */
quietmode = -1;
break;
case 'x': /* --exec <executable> */
execname = optarg;
break;
default:
badusage(""); /* message printed by getopt */
}
}
if (start == stop)
badusage("need one of --start or --stop");
if (!execname && !pidfile && !userspec)
badusage("need at least one of --exec, --pidfile or --user");
if (!startas)
startas = execname;
if (start && !startas)
badusage("--start needs --exec or --startas");
}
static int
pid_is_exec(int pid, const struct stat *esb)
{
struct stat sb;
char buf[32];
sprintf(buf, "/proc/%d/exe", pid);
if (stat(buf, &sb) != 0)
return 0;
return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
}
static int
pid_is_user(int pid, int uid)
{
struct stat sb;
char buf[32];
sprintf(buf, "/proc/%d", pid);
if (stat(buf, &sb) != 0)
return 0;
return (sb.st_uid == uid);
}
static int
pid_is_cmd(int pid, const char *name)
{
char buf[32];
FILE *f;
int c;
sprintf(buf, "/proc/%d/stat", pid);
f = fopen(buf, "r");
if (!f)
return 0;
while ((c = getc(f)) != EOF && c != '(')
;
if (c != '(') {
fclose(f);
return 0;
}
/* this hopefully handles command names containing ')' */
while ((c = getc(f)) != EOF && c == *name)
name++;
fclose(f);
return (c == ')' && *name == '\0');
}
static void
check(int pid)
{
if (execname && !pid_is_exec(pid, &exec_stat))
return;
if (userspec && !pid_is_user(pid, user_id))
return;
if (cmdname && !pid_is_cmd(pid, cmdname))
return;
push(&found, pid);
}
static void
do_pidfile(const char *name)
{
FILE *f;
int pid;
f = fopen(name, "r");
if (f) {
if (fscanf(f, "%d", &pid) == 1)
check(pid);
fclose(f);
}
}
static void
do_procfs(void)
{
DIR *procdir;
struct dirent *entry;
int foundany, pid;
procdir = opendir("/proc");
if (!procdir)
fatal("opendir /proc: %s", strerror(errno));
foundany = 0;
while ((entry = readdir(procdir)) != NULL) {
if (sscanf(entry->d_name, "%d", &pid) != 1)
continue;
foundany++;
check(pid);
}
closedir(procdir);
if (!foundany)
fatal("nothing in /proc - not mounted?");
}
static void
do_stop(void)
{
char what[1024];
struct pid_list *p;
if (cmdname)
strcpy(what, cmdname);
else if (execname)
strcpy(what, execname);
else if (pidfile)
sprintf(what, "process in pidfile `%s'", pidfile);
else if (userspec)
sprintf(what, "process(es) owned by `%s'", userspec);
else
fatal("internal error, please report");
if (!found) {
if (quietmode <= 0)
printf("no %s found; none killed.\n", what);
exit(exitnodo);
}
for (p = found; p; p = p->next) {
if (testmode)
printf("would send signal %d to %d.\n",
signal_nr, p->pid);
else if (kill(p->pid, signal_nr) == 0)
push(&killed, p->pid);
else
printf("%s: warning: failed to kill %d: %s\n",
progname, p->pid, strerror(errno));
}
if (quietmode < 0 && killed) {
printf("stopped %s (pid", what);
for (p = killed; p; p = p->next)
printf(" %d", p->pid);
printf(").\n");
}
}
int
main(int argc, char **argv)
{
progname = argv[0];
parse_options(argc, argv);
argc -= optind;
argv += optind;
if (execname && stat(execname, &exec_stat))
fatal("stat %s: %s", execname, strerror(errno));
if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
struct passwd *pw;
pw = getpwnam(userspec);
if (!pw)
fatal("user `%s' not found\n", userspec);
user_id = pw->pw_uid;
}
if (pidfile)
do_pidfile(pidfile);
else
do_procfs();
if (stop) {
do_stop();
exit(0);
}
if (found) {
if (quietmode <= 0)
printf("%s already running.\n", execname);
exit(exitnodo);
}
if (testmode) {
printf("would start %s ", startas);
while (argc-- > 0)
printf("%s ", *argv++);
printf(".\n");
exit(0);
}
if (quietmode < 0)
printf("starting %s ...\n", startas);
*--argv = startas;
execv(startas, argv);
fatal("unable to start %s: %s", startas, strerror(errno));
}

120
contrib/zefram-patches Normal file
View File

@ -0,0 +1,120 @@
Date: Mon, 14 Apr 1997 15:39:08 +0100 (BST)
From: Zefram <zefram@dcs.warwick.ac.uk>
Message-Id: <25042.199704141439@stone.dcs.warwick.ac.uk>
Subject: SysVinit patch
To: miquels@drinkel.cistron.nl
Hi. Enclosed is a patch for SysVinit that I am finding tiresome to
keep updating; you might like to fold it into your official releases.
It does the following:
* shutdown: use /etc/shutdown.allow if an option -s is given instead
of testing for a controlling tty. The tty check was inflexible and
unreliable.
* sulogin(8): refer to inittab(5) instead of inittab(4).
* sulogin: use libc passwd/shadow functions instead of home-grown ones
(there's just no point in using the special version).
* shutdown/sulogin: don't rely on the username "root" -- it's the UID
that counts.
-zefram
begin 644 initdiffs.gz
M'XL(``IG43,"`^T[:U/;R+*?E5_1>&L3&\G&#Y[FD%H")/%9)U"8G-0](44)
M>62KD"6M1K+7)YO_?KM[1K)DFP"[V:T]=2^5`FFFIZ??W=.C##W7A;H3@YS+
MJ1=X2;W=V#W8DN,T&8:SH+%?GC`+,\\V-S?O76:\CCWX9QI`:QO_=3N[W68;
M6@<'N\_J]?K].(T!+CF.8FAUH-WI-G>Z.QU:MD>;%7]X\U;+:NT!OP(T7L&6
MO/6"'!N-7;Z"3W!=3^BY=PE2./#YV48^'M^-`\?%(9J&Q)L(7M3#R9D=!UXP
MJD^$E/9(*)CKRM>O7YD#M34^U?_0UO*I>Z\3P^Z!M;>MQ$"DX>M^*R--_!KY
M-DHZC.>0H0L#2,8"G'`RL8,A^%X@<,!.8.;Y/MP*I#5((`G!]GU$D4H1R\:"
M!),>OGSY`E"7]-*[@&OWU75=7KL7^'X6R#36"&U>#'::C,/8DV)(6$E(0%)B
M*M`4$C$!3X(?CD8(X04-Q'(UQA'\%X3Q!,F8$Z(AS,8BH,TR.>..!.0@!,[>
MSFF.[`K'J_LU"_'PBI,D]NO'?E(_%3[!1S%*0@P;``,A%!7"2;R0</>.'0=G
MX20,DCCT%4^WP@]GX(8Q3$+DS0M<(HM6-)0X2"Z0RR53)DNF1V^$!N`C$:,E
MP/:^WJJ;.U9K8=?(TLG59;]^W+^JGY[UB64;:=`\6,2U$PLD)AB!'8`=17$8
MQ9Z="$`UHMJ]@+'TMD3B;)%T$OL6L324C"?"#J32EIB*>!ZB,<S&(8QME--X
M+CT4+M@L$T2#Q"O3"63H"[@3\]O0CH>H@4#IM:!2YA"N0B)URA:%^UGH`DL*
MI+7.6#AW+!I4B.<R(\IH_H.*92,J6@B:,.(A4D.7MYQZ<9(BH9HPV8">>[^A
MN'$X*9@*T>0EB@99(((0NQZRF0DOUQNB"6<:)RD"N2,'Z3'_`7E6A#J2C`&)
M1H(#&[V/*&=),]:9EXP5A"<38B028>23X2C?B46)872F)2ZAJAGI;4WM>"M.
M@ZTTF41(5ZT!YX$_)[[<A9A"*9:E*DD,:-9Q&"::GWQ/BX1"(0'1H$TY@CSF
M'`F.9^C*V23,8B]13J3C"UF^C*!%?P-767`FN2XZ]"H-^9;D)BJZMJU6>SL+
M8O_O`FM=@#1+;O![7"`W/H10D1L11131K/^[OE"2+QLWBF+5]%6X^%.,?_A`
M.>;<6SHYWRK''.,J%7"<CJBN:C6[.[O=UL'#Y9CSM'+LP&H5RA!\V\D<&#8-
M`\L%E,`P1"$D,"(GBL-T-`;:&&ZY)""QAFDLA3\57''H=4Z7/,3!Y$U.X:.K
M#^>`*J8BJ9!,<_B$\KG$S81OSS%Y)S.!ECCHO;DZNWP'5//@\\^]?I]3.A%`
M:5POQG43^PY=F*J8A1/*=4ZH]N1?*%V"ZQKOO%]2I'2*2P>3$,N%X#:-1Q9,
M>%S^-(R]X$[X#0<M/<8"(O`5DG42W6M:>[M9(3`-/2(!C:Q:P]<OM,S%,!<D
M;E4F0Q''%%F,R@<"Z5XGD(L&/M7OXK$;.)_Q20GG,Q<I\$F7FIGY?KX.*HC7
MJ%PGA*!^UP7^&8;!BP10\%2*96@M="=\)12-I76Q7A>+6\PL8+L)2B[7U!+P
M6`./;7\M*%G37LO:R^OM[R`)^=\IBK5&LF_M=Q9^MX?E?^YX.>(@IW[9_ZXK
M7`95V`=QG,5$[(%KRV290$?CR?QQU0V7%JSWQ4S6Y(MW%$BE-PILGQ>;B\52
M[_9XARSOCM+A'%?A&KR">6243B@/4];'O6TZ%VU`E6J$ZTJ`>:Q2PT6(I'9(
M1H7')R^IMOAE_=FKO;MOM?<*XF^CS[;1:;/(AT1A:/.&08A$PA$T#_-1+</2
M6(26S0.F'D#I$=\YT.M>_PPVW4B].6,[ADV2.R>33YWVY\+$;>I^:K7W<6@M
MZ?O;5J=SD(47XI!^8U1RHGF5<-[X6+7X%E1:2A[/ZCB_M<FG)DRF,X%V.D6=
M4!*FPY)/*D6;G7BD2]C<X@4(64V<D4BB41Q5FS78.(+LK0;/G_,+\HTO1T?0
MPA%>1C]5-T+.W3`2075P>MSOGW]$:N)*C9&\_]#OU]#[ZT28@72]#]=28A&E
M,X%2+-;_'/85C8:GY*NP7&)Z@34U3@8\&V/%4G61:EE%"5N`(K8P_M04+89!
M#)/HFY^)H1<_O(#??H/"P'7PHL:$>D$J#O,E'KR$3FMY!C-459(4$,$A;,KH
M$&1DFC46ZR;-9!CY1;-A+$S",TW<EM0Z3".BJ\807YEOWO8?T&G7H+#B<X['
M=7RLE%`-O"@7\PP=V+_+0TBIY**BT?6HKY"74JJ#4!+?!HW=A'>D_RH&'C:)
M-$'?K*Y3KK&PND1W!G1O@<LS/*]S4?BODVP79BU-ZB_3Y":91X)0?AB<7=Y<
M7)Z?G`T&RV*6.GVP0BM;0S'=^E%6+-`HJ$=26ZA*)G:B0)_+I(8";*Y3*((U
M9'(3(S)X#LU?7[\^4=;?_+6YW5Q:DG%Y24F"V/-G]ES"^<\ECL@Y)U'&&`F`
M_`&75-AYFID)&EJ\IJG(,6XQHM^IYZ_?D"F55VCJ.K3F6Y,1*A\!92ZDMJ+!
MX#C:I-J*Z-Q`0@.BM`B42U/1_>'JYOWQN[-![]]GN>NL$EZD7!DM_Q+!4%M+
MP3`U-VP7,UMFO.1>3H1I_$5?+4:9D_/W@_/^&4IUMA)EJ#S,ZPPW0ICK^)&U
M?>,Z5DDEPU+R*\V8D6<;S26%9&0.5-2]T)9.&4T=U91/T;1RJJJC_`AGJYCJ
M'(L2WA3I='[!JB=PYTEWU/6ZFK&S\]<U53N!(?$`YHRK#C-*66Q_SVH?M%46
M6Y<\.GMMJ[/?7N2]3GL'!_(C.RN+_RP2"<<_(AVIPN=#-:_UBUG?<&P\E;V0
M+[HJR7#BFX1#05S2O)$GPY9:D"UF'HRA<.W43[KZU=`58C:M@0WU^E6G/!,X
MU>*&IV'6"DSQ5#<GIPA&#;6WRF)Z>PI9CTI,)EOE1_&">X99*B>.+)#A@U7-
M)B'`DT7IY*O/NPU0D6(8"LD5':X/J27I<%VJ?C($O^!!V7/G%J%@&7LJQ#AT
M@D9HW#X-T*ZG:$2TD^TX81HDFO<L.YH/9T?S@>QH/CT[FO=F1_/W94?SP>QH
MDG68#V5'LYP=V8[^8'8TGYP=U:Y/RX[FT[*C^>CL:#XJ.V90&X.;WN#D[:7.
MDN05M75P3\BB]TMC35XSGY#7S#^2U\SEO&86\YJI0F5F<\6\EIO4M_*:N9K7
MS"?E-?.[Y#5S-:^9H!E;Y#7-I8Z[.J]Q1*%S3^BNG"95J6ZK)J'.=<NL#4XO
M>J=KHB\&>5?B&4OS].,0#?8Y[H-TW-=F2[E!N>;2,YM8UV3+YOC*<R`B@%WJ
ML37;W>W._3VV?-636FS[>8L-H#%X"Z=G@Y/+WL55[_R]ND?4>/&%+#^8AG>E
MB['J?HU:M7PK5NA3CT)NR%*[%Z6/HF93(Y=\1J=C[47#D"\*551#E\IZZ]1U
MU4WUZG9-M5QQOYZZ74%KE2$U<F-/<$=9_(IY,.%.LJ8V)TGEI<B6?%6HN]/4
MJ0?7MT>(A,V!)JB7,@GY8A.J8F1!O]<_K_$MY86Z0V!191>T?T=1[?PM1/6`
M*SCW&:[S#5=PC(](U#]3']K;T-KIMMK=SNZ#KN`8[T+M"MO01`=J=EO?<(7V
M-E:HA;[+MM5I9OK^P0L</\7"\1^N$R1^8_RR-*B;34NCT6Q(0V81<&QC%%H&
MY+Y"*%>PSN66%SJ+[5RXN7GS_L--O_?J\OCR?VYNX.41[*XOISO6=C-S[!^P
MD*4[^9.W9R<_WZ#=&JV5T7>G.SR*YX-LXN)X,/AX:E2X."/#F`TKA>G!V^/3
M\X]Z6C%6*:!]U7L_>(NSZC,&FGF6M9?^A2&?+L>/H/)3]8>:UA>T&GO0VJ^C
MFNND6G@W'30JA^HP@,HXN/_P0"5A>]%Y^JHVV]JD(\^F,1#TX0`639Y]Z^>7
M3U/;3X7Z(B#A$-]@:#K8<3M8BJ2JR-W$I98F'5?1J?1+=ORC=QJ-D1E\II.6
M/@YOJ3:^\4:H&SPZ5+-[S<)XJ/Q7=?LI"6$5D#IZ>@B;6)P1>#3CQ,T=Z0T\
M4R54CB_!HI$=TN2BC;>`9)*IEOK4WMG]O#(CRU.*0>X#4JIC^K'8-UY3.S7$
MHE&&$P'Z3,37;?9P2AW'A@+<(B1D\]'LAF[D2+W<23@L3&BJ<:HT/!).*&ET
MD$88_3Y@""S-#ST2<&6K-"C'PO=74*59P[.`?3%$H\OY7MEYEO"/%@D?80TD
M)\:B3L'4&*L18^T<!YC[2?;ZZ$<3*+(-+3(LR%GAGHKUN=ZI[F@H*):7/F<S
M,7S$(9U8@$K19YR-,CFZ9\,EHP)E&7>Q%-E116R-X8Q%$<M<@'D$.^J9#/MY
M21T6V904$0XC/CK.*\@J.4)M:>[!J2)^UNM]Z(N`J.#'@+'*RX!4+M8R+H_8
MW-6;KH<W2#\;Y;/51EE=/1411.#$\RC!3).K"\,#>K4WU("8\"A:N'B81:$I
M,RAJD[03+5O0TD42%HZ2BV"5PMWL8XD`57B_E65<Z)CC#:LE#:*A+!EER86O
MBB:HBA/"P3?Z=`G-<=#6P"J4Y_`6<*61%+U<M_27C*BB+6"EGN9$<8]_K95.
M.59J:A\IH16/DD]P*?FG^]23K;*H-YGP-P1*'I:&(UY0/Q;??7U_FU3:RWSQ
MFXK/+71CO8G^+HT_<G_@S9><8%$(<"H^EG?,6U&L#7@?)OKKPMP5@E`MT,F.
M[W,I`^)1>286GQ#*.R]2+8%A&M,IDRKC+*EOZ(J!+J.8SOQJV=`97)=]$/KD
M9,G\4,TM$C2M^]3:58U-A0T91,.F"1ZD"SWO4*<?+=?*&V^Z7&[PEX8V3HN`
M,G9V'YDOJ9)4J&^COU*LG_(2Q2F:G1TG:53K@E[FNGXJQZ1!E(J^R:.OK-I[
M5FL_OZI<DOZ?7`BAKK(XL(1D:5A&-"C7Q<DGE3IJP_75SF)NN>!9S-Q;\RQ`
MRF7/8GRI\EE,%(N?PDYKZI^(B2+CG.&B:O,1D?G$I@\5N-EHPX?>*30S$;,2
ME5$5XW*FDE*)!`]GVSRU%D)8'E'J+]=DO;\BZ97W5G</S47"D[E$980&D9-*
MQE$0[GK17A0=]4=9"H`E1+R?\"4?8[(X*QE$1C?X%Q/<NBU4`JL,RFP^?CN5
M\4H2H"YW<>/#0@#^6\9?]<Y\_961^$?YK3AL@1;T=XW&:_L;!WM6IYEW^PP5
M<`V4CX/"&6/$LV!W6Z'$>D8$TVKE[?F[,R113;:4.61S_?,WU):N9!?&*P!T
M`;`T6T`]>'O6[^.P3'51K^:U"ZL.S+;5WLG_Y\%W)+AHX_>1O0KS:.+7-F3V
M]ZW.P4XN_3Q,K76*0MA1]6RK6*UR<5NH*PJA.[^_5)!K8A8&+?CM-X;(OL[!
MPI=C<35:L*TC[,J`^BI`W;1J[FF7FN[3=':LSO9"94_D<HFQ<@C5+?B_G*__
)!9>7)7O2-```
`
end

635
doc/Changelog Normal file
View File

@ -0,0 +1,635 @@
sysvinit (2.87dsf) world; urgency=low
* Fix typos and do minor updates in the manual pages.
* Correct section of mountpoint(1).
* Document -e and -t options for telinit in init(8).
* Update address of FSF in the COPYRIGHT file.
* Document in halt(8) that -n might not disable all syncing.
Patch by Bill Nottingham and Fedora
* Adjust output from "last -x". In reboot lines, print endpoint
of uptime too. In shutdown lines print downtimes rather than
the time between downs. Fix typo in string compare in last.c.
Patch by Thomas Hood.
* Improve handling of IPv6 addresses in last. Patch from Fedora.
* Document last options in usage information, previously only
mentioned in the manual page.
* Add new option -F to last, to output full date string instead
of the short form provided by default. Patch from Olaf Dabrunz
and SuSe.
* Adjust build rules to make sure the installed binaries
are stripped.
* Increase the compiler warning level when building.
* Fix utmp/wtmp updating on 64-bit platforms. Patch by Bill
Nottingham and Fedora.
* Avoid unchecked return value from malloc() in utmpdump.
Patch from Christian 'Dr. Disk' Hechelmann and Fedora.
* Make sure to use execle and no execl when passing environment to
the new process. Patch from RedHat.
* Correct init to make sure the waiting status is preserved across
re-exec. Patch from RedHat.
* Correct init to avoid race condition when starting programs during
boot. Patch from SuSe.
* Allow 'telinit u' in runlevels 0 and 6. Patch from Thomas Hood.
* Change install rules to make pidof an absolute symlink. Patch from
Thomas Hood.
* Improve error message from init if fork() fail. Patch found in Suse.
* Add support for SE Linux capability handling. Patch from Manoj
Srivastava, adjusted to avoid aborting if SE policy was loaded in
the initrd with patch from Bill Nottingham and Fedora.
* Add -c option to pidof for only matching processes with the same
process root. Ignore -c when not running as root. Patch from
Thomas Woerner and Fedora.
* Adjust init to terminate argv0 with one 0 rather than two so that
process name can be one character longer. Patch by Kir Kolyshkin.
* Make sure bootlogd exit with non-error exit code when forking of
the child successfully.
* Add bootlogd option -s to make it possible to control the use of
fdatasync(). Patch from Thomas Hood.
* Add bootlogd option -c to tell it to create the log file if it does
not exist. Patch from Thomas Hood.
* Let bootlogd also look at ttyB* devices to work on HPPA. Patch
from Thomas Hood.
* Change init to use setenv() instead of putenv, make sure the PATH
value is usable on re-exec. Patch from Thomas Hood.
* Add usleep in killall5 after killing processes, to force the kernel
to reschedule. Patch from SuSe.
* Modify pidof to not print empty line if no pid was found.
* Modify init and sulogin to fix emergency mode's tty, making sure ^C
and ^Z work when booting with 'emergency' kernel option. Patch from
Samuel Thibault.
* Modify init to allow some time for failed opens to resolve themselves.
Patch from Bill Nottingham and Fedora.
* Modify init to shut down IDE, SCSI and SATA disks properly. Patches
from Sebastian Reichelt, Werner Fink and SuSe.
* Modify wall to use UT_LINESIZE from <utmp.h> instead of hardcoded
string lengths. Patch from SuSe.
* Change wall to make halt include hostname in output.
* Change killall to avoid killing init by mistake. Patch from SuSe.
* Change killall5 to use the exit value to report if it found any
processes to kill. Patch from Debian.
* Add option -o opmitpid to killall5, to make it possible to skip
some pids during shutdown. Based on patch from Colin Watson and
Ubuntu.
* Add references between killall5 and pidof manual pages. Patch from Debian.
* Modify killall to work better with user space file system, by
changing cwd to /proc when stopping and killing processes, and
avoiding stat() when the value isn't used. Also, lock process
pages in memory to avoid paging when user processes are stopped.
Patch from Debian and Goswin von Brederlow with changes by Kel
Modderman.
* Change shutdown to only accept flags -H and -P with the -h flag,
and document this requirement in the manual page.
* Change reboot/halt to work properly when used as a login shell.
Patch by Dale R. Worley and Fedora.
* Let sulogin fall back to the staticly linked /bin/sash if both roots
shell and /bin/sh fail to execute.
-- Petter Reinholdtsen <pere@hungry.com> Sun, 12 Jul 2009 19:58:10 +0200
sysvinit (2.86) cistron; urgency=low
* Fixed up bootlogd to read /proc/cmdline. Also keep an internal
linebuffer to process \r, \t and ^H. It is becoming useable.
* Applied trivial OWL patches
* Block signals in syslog(), since syslog() is not re-entrant
(James Olin Oden <joden@malachi.lee.k12.nc.us>, redhat bug #97534)
* Minor adjustements so that sysvinit compiles on the Hurd
* killall5 now skips kernel threads
* Inittab entries with both 'S' and other runlevels were broken.
Fix by Bryan Kadzban <bryan@kadzban.is-a-geek.net>
* Changed initreq.h to be more flexible and forwards-compatible.
* You can now through /dev/initctl set environment variables in
init that will be inherited by its children. For now, only
variables prefixed with INIT_ can be set and the maximum is
16 variables. There's also a length limit due to the size
of struct init_request, so it should be safe from abuse.
* Option -P and -H to shutdown set INIT_HALT=POWERDOWN and
INIT_HALT=HALT as environment variables as described above
* Add "mountpoint" utility.
* Slightly better algorithm in killall5.c:pidof()
* Added some patches from fedora-core (halt-usage, last -t,
sulogin-message, user-console)
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 30 Jul 2004 14:14:58 +0200
sysvinit (2.85) cistron; urgency=low
* Add IPv6 support in last(1)
* Sulogin: even if the root password is empty, ask for a password-
otherwise there is no way to set a timeout.
* Removed support for ioctl.save.
* Turned of support for /etc/initrunlvl and /var/run/initrunlvl
* Fixed warts in dowall.c ("Dmitry V. Levin" <ldv@altlinux.org>)
* Fix init.c::spawn(). The "f" variable was used both as file descriptor
and waitpid(2) return code. In certain circumstances, this leads to
TIOCSCTTY with wrong file descriptor (Vladimir N. Oleynik).
* Fix fd leak in sulogin (Dmitry V. Levin).
* More error checking in all wait() calling code (Dmitry V. Levin).
* Fix argv[] initialization in spawn() (Dmitry V. Levin).
* Change strncpy to strncat in most places (Dmitry V. Levin).
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 15 Apr 2003 16:37:57 +0200
sysvinit (2.84) cistron; urgency=low
* Don't use /etc/initlvl interface for telinit; only use /dev/initctl,
and give a clear error when that fails.
* Add -i/--init command line flag to init - this tells init
'behave as system init even if you're not PID#1'. Useful for
testing in chroot/jail type environments.
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 27 Nov 2001 13:10:08 +0100
sysvinit (2.83) cistron; urgency=low
* Fix bug in shutdown where it didn't check correctly for a
virtual console when checking /etc/shutdown.allow
* Fix race condition in waitpid() [Andrea Arcangeli]
* Call closelog() after openlog()/syslog() since recent libc's
keep the logging fd open and that is fd#0 aka stdin.
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 2 Oct 2001 23:27:06 +0200
sysvinit (2.82) cistron; urgency=low
* Print out correct version number at startup.
* Fix spelling of initttab in init(8)
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 23 Aug 2001 17:50:44 +0200
sysvinit (2.81) cistron; urgency=low
* Fix typo/bug in killall5/pidof, -o option failed to work since 2.79.
Reformatted source code to prevent this from happening again.
* shutdown.8: applied redhat manpage update
* sulogin: applied redhat sysvinit-2.78-sulogin-nologin.patch
* sulogin: applied redhat sysvinit-2.78-notty.patch
* sulogin: applied redhat sysvinit-2.78-sigint.patch
sysvinit (2.80) cistron; urgency=low
* Grammar/spelling fixes in shutdown.c (Christian Steinrueck)
* Don't set controlling tty for non-(sysinit,boot,single) runlevels
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 26 Jul 2001 13:26:56 +0200
sysvinit (2.79) cistron; urgency=low
* New upstream version
* several fixes to wall by Tim Robbins <fyre@box3n.gumbynet.org>
* Several extra boundary checks by Solar Designer
* Make /dev/console controlling tty
* Stricter checks on ownership of tty by mesg(1)
* Documented and restricted -n option to wall(1)
* Make it compile with glibc 2.2.2
* Document IO redirection in wall manpage (closes: #79491)
* Update README (closes: #85650)
* Fix init.8 manpage (closes: #75268)
* Fix typo in halt(8) manpage (closes: #67875)
* Check time argument of shutdown(8) for correctness (closes: #67825)
* Check for stale sessions in last(1) (Chris Wolf <cwolf@starclass.com>)
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 4 Jul 2001 15:04:36 +0200
sysvinit (2.78-2) frozen unstable; urgency=high
* Change "booting" to "reloading" message at reload
* Add "-z xxx" dummy command line argument (closes: #54717)
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 11 Feb 2000 12:17:54 +0100
sysvinit (2.78-1) unstable; urgency=low
* 2.78 will be the new upstream version, I'm skipping 2.77
* Shutdown now calls sync before switching the runlevel to 0 or 6,
or before unmounting filesystems if -n was used (closes: #46461)
* Some cosmetic changes to init.c (closes: #32079)
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 30 Dec 1999 20:40:23 +0100
sysvinit (2.77-2) unstable; urgency=low
* Fix last -i option
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 5 Oct 1999 21:51:50 +0200
sysvinit (2.77-1) unstable; urgency=low
* Write reboot record into utmp file as well to make rms happy
* Fork and dump core in / if SIGSEGV is received for debugging purposes
* Patch by Craig Sanders <cas@vicnet.net.au> for "last" -i option
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 4 Aug 1999 11:16:23 +0200
sysvinit (2.76-4) unstable; urgency=low
* Change dowall.c to handle Unix98 ptys correctly
* Add comment in rcS about usage of setup.sh and unconfigured.sh
* Shutdown now removes nologin file just before calling telinit
* SEGV handler now tries to continue after sleep of 30 seconds.
On a 386-class processor it also prints out the value of EIP.
* Fix for racecondition in check_init_fifo() by Richard Gooch
-- Miquel van Smoorenburg <miquels@cistron.nl> Sat, 8 May 1999 17:22:57 +0200
sysvinit (2.76-3) frozen unstable; urgency=high
* Small bugfix to last.c courtesy of Danek Duvall <duvall@emufarm.ml.org>
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 12 Jan 1999 12:12:44 +0100
sysvinit (2.76-1) frozen unstable; urgency=high
* Fix bug in check_pipe() which crashes init on the Alpha.
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 3 Nov 1998 11:09:13 +0100
sysvinit (2.75-4) unstable; urgency=low
* Change sulogin password buffer to 128 characters.
* Don't print control characters in dowall.c
* Try to open getenv ("CONSOLE"), /dev/console and /dev/tty0 in order.
For backwards compatibility when you try to boot a 2.0.x kernel
with a linux > 2.1.70 /dev/console device.
* Change src/Makefile for non-debian systems (mainly, RedHat)
* Try to create /dev/initctl if not present; check every time to see
if the dev/ino of /dev/initctl has changed and re-open it. This should
help devfs a bit.
* Send SIGUSR1 to init at bootup to let it re-open /dev/initctl;
again in support of devfs.
* Moved pidof to /bin (it's only a link to killall5 anyway)
-- Miquel van Smoorenburg <miquels@cistron.nl> Mon, 5 Oct 1998 14:03:14 +0200
sysvinit (2.75-2) frozen unstable; urgency=medium
* Fix last.c again.
* Add check to see if /dev/initctl is really a FIFO
* In ifdown.c first down all shaper devices then the real devices
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 2 Jun 1998 22:43:01 +0200
sysvinit (2.75-1) frozen unstable; urgency=low
* Rewrote last.c to be much more memory friendly and correct,
thanks to Nick Andrew <nick@zeta.org.au> and
David Parrish <dparrish@zeta.org.au>
* Fixes bugs:
#21616: sysvinit: sulogin thinks md5 root password is bad
#21765: sysvinit: Typo in `killall5.c'
#21775: sysvinit: sysvinit does not support MD5 hashed passwords
#21990: /usr/bin/last: unnecessary memset and off-by-one bug
#22084: sysvinit 2.74-4: SIGPWR missing on sparc
#21900: init, powerfail events, and shutdown.allow
#21702: init 0 does not work as expected...
#21728: sysvinit: Typo in `init.c'
#22363: sysvinit: discrepance btw. manpage and /sbin/init
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 19 May 1998 11:02:29 +0200
sysvinit (2.74-4) frozen unstable; urgency=medium
* Add -o option to last to process libc5 utmp files.
* Buffer overflow fixed in init.c (not very serious; only exploitable
by root). Thanks to Chris Evans <chris@ferret.lmh.ox.ac.uk>
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 15 Apr 1998 17:04:33 +0200
sysvinit (2.74-1) unstable; urgency=low
* Should compile with glibc 1.99 :)
* Change behaviour of reboot(1) and halt(1) so that the default when
the runlevel can't be determined is to call shutdown.
* Added re-exec patch from Al Viro (21 Feb 1998):
'U' flag added to telinit. It forces init to re-exec itself
(passing its state through exec, certainly).
May be useful for smoother (heh) upgrades.
24 Feb 1998, AV:
did_boot made global and added to state - thanks, Miquel.
Yet another file descriptors leak - close state pipe if
re_exec fails.
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 12 Mar 1998 17:42:46 +0100
sysvinit (2.73-2) unstable; urgency=low
* Change _NSIG to NSIG for 2.1.x kernel includes.
-- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 8 Jan 1998 16:01:02 +0100
sysvinit (2.73-1) unstable; urgency=low
* Use siginterrupt, now that system calls are restarted by default.
Main symptom was that the sulogin timeout didn't work but there
might have been more hidden problems.
* Kill process immidiately if turned off in inittab
* Fixed sulogin check on tty arg.
* Use strerror() instead of sys_errlist
* wall now supports a '-n' option to suppress [most of] the banner.
Debian doesn't use sysvinit's wall, but apparently Redhat does.
* Add '-F' (forcefsck) option to shutdown
* Close and reopen /dev/initctl on SIGUSR1 (mainly for a /dev in ram)
-- Miquel van Smoorenburg <miquels@cistron.nl> Sat, 3 Jan 1998 16:32:39 +0100
sysvinit (2.72-3) unstable; urgency=low
* Add extra fork() in dowall.c to avoid hanging in rare cases
-- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 22 Oct 1997 14:44:00 +0200
sysvinit (2.72) unstable; urgency=low
* Applied manual page patches by Bill Hawes <whawes@star.net>. Thanks Bill!
* Applied patches to the sample Slackware scripts by
"Jonathan I. Kamens" <jik@kamens.brookline.ma.us>
* Fix halt and reboot runlevels 0 & 6 check.
* Only say "no more processes left in runlevel x" once
* Fix race condition with SIGCHLD in spawn()
(thanks to Alon Ziv <alonz@CS.Technion.AC.IL>)
* Compress all manpages (missed 2)
* Compiled for libc6
* Added poweroff patch by Roderich Schupp <rsch@ExperTeam.de>
-- Miquel van Smoorenburg <miquels@cistron.nl> Sun, 12 Oct 1997 17:20:17 +0200
sysvinit (2.71-2) frozen unstable; urgency=low
* Print 2.71 instead of 2.70 on startup :)
-- Miquel van Smoorenburg <miquels@cistron.nl> Mon, 5 May 1997 12:45:25 +0200
sysvinit (2.71-1) frozen unstable; urgency=high
* Added code for updwtmp() in utmp.c for glibc (2.0.3)
* Fixed all programs to use functions from utmp.c and getutent()
* Do not try to clean up utmp in init itself (Bug#9022)
* Removed sync() from main loop.
* Hopefully fixes bug #8657 (shutdown signal handling)
-- Miquel van Smoorenburg <miquels@cistron.nl> Sat, 26 Apr 1997 19:57:27 +0200
sysvinit (2.70-1) unstable; urgency=low
* Respawn fix
* Removed StUdLy CaPs from source code
* Moved files in source archive around
* Fixes for glibc (utmp handling, signal handling).
* Fixed '-d' option to last (now also works without '-a').
* Added extra checking in last.c to prevent showing dead entries
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 7 Feb 1997 15:31:30 +0100
sysvinit (2.69-1) frozen unstable; urgency=medium
* Fixed bug that can throw X in a loop (or any other app that reads from
/dev/tty0)
-- Miquel van Smoorenburg <miquels@cistron.nl> Sun, 1 Dec 1996 15:32:24 +0100
sysvinit (2.67-1) frozen unstable; urgency=high
* Fixes problem with /dev/console being controlling terminal of some
daemons
* Puts copyright file in the right place
-- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 15 Nov 1996 12:23:33 +0100
sysvinit (2.66-1) unstable; urgency=medium
* Skipped 2.65. A development 2.65 got out by accident and is apparently
being used..
* Also compiles and runs with GNU libc (and on the Alpha)
* Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
* Fixed init panic'ing on empty lines in /etc/inittab
* Changed default PATH to include /usr/local/sbin
* Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait
This allows using ^C to interrupt some parts of eg the boot process.
* Remove old symlink in /var/log/initlvl; let init check both
/var/log and /etc itself.
-- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 29 Oct 1996 13:46:54 +0100
2.66 29-Oct-1996
- Skipped 2.65. A development 2.65 got out by accident and is apparently
being used..
- Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
- Fixed init panic'ing on empty lines in /etc/inittab
- Changed default PATH to include /usr/local/sbin
- Ported to Linux/Alpha and GNU libc.
- Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait.
This allows using ^C to interrupt some parts of eg the boot process.
- Remove old symlink in /var/log/initlvl; let init check both
/var/log and /etc itself.
2.64 28-Jun-1996
- Init checks CONSOLE environment variable on startup (overrides /dev/console)
- Init sets CONSOLE variable for all its children.
- Wtmp(): when zeroing out old utmp entries, keep ut_id field
- Wtmp(): try to re-use ut_id field if possible.
- SetTerm(): only read from /etc/ioctl.save if written once.
- Included start-stop-daemon, C version (source only).
- Fixed wait() for the emergency shell.
- killall5: ignore signal before doing kill(-1, pid).
2.63 14-Jun-1996
- Fixed preinst script for Debian
- Fixed init.c to become init daemon if name is init.new
- Fixed pidof to not return PIDs of shell scripts
2.62-2 09-Jun-1996
- Changed debian /etc/init.d/boot script to create a nologin file
at boot and to remove it just before going multiuser.
2.62 31-May-1996
- Decided to release a 2.62 version with a BIG WARNING about upgrading
init in it. Will send a patch to Linus for the linux/Documentation/Changes
file so that 2.62 or later is mentioned as the version to upgrade to.
- Added docs for Slackware
2.61-3 29-May-1996
- Fixed debian/etc/init.d/network for the lo device.
- Added "-xdev" to the cd /tmp && find in debian/etc/init.d/boot
- Made remove time for files in /tmp configurable.
2.61 29-Apr-1996
- Changed /etc/init.d/boot script again
- Fixed problem in init.c with trailing whitespace after entries in inittab
- Fixed killall5 problems
- Added manpage for lastb
- Added SHELL= environment variable to sulogin
- Fixed sulogin & shadow problems
- Added timeout option to sulogin
2.60-2 16-Apr-1996
- Fixed sulogin (didn't work if root wasn't first entry in shadow file)
- Fixed mesg for systems with "tty" group (such as Debian)
- Fixed nsyslog() in killall5.c
2.60 01-Apr-1996
- Fixed race condition in init.c, resulting in hanging shutdowns.
Courtesy of Max Neunhoeffer <Max.Neunhoeffer@urz.uni-heidelberg.de>.
- Fixed debian/etc/init.d/boot for swapon and mdadd
- Added architecture to debian.control
- Added manpages for rc.boot and rc.local
- Updated inittab manpage for 4-character runlevel field
- Added debian replaces for bsdutils < version_without_mesg
- Fixed init.c so that it also works with kernels 1.3.81 and up
2.59 10-Mar-1996
- Init logs less to syslog (suspected to hang in syslog() or openlog() )
- removed closelog() from init.c
- removed time check of runlevel record in halt.
- Added options to last to get hostname from ut_addr field
- Added last and mesg to installation targets
- rewrote /etc/init.d/boot a bit.
2.58-2 04-Jan-1996
- Changed etc/init.d/rc to do a stty onlcr
- Added /var/log/initrunlvl symlink
2.58-1 31-Dec-1995
- Added the latest debian files.
- Added support for 4-character id fields (if you have libc5).
- Fixed pidof (in killall5) parsing of /proc/.../stat
- Save restore GMT setting in /etc/init.d/boot
2.57d 03-Dec-1995
- Added sulogin
- Added "-b" flag to init, gives a shell before
anything else (in case the startup scripts are screwed)
- Moved fastboot to /fastboot
- Folded in Debian patches.
- Removed old scripts
- Added debian /etc/directory.
2.57c 08-Oct-1995
- Changed over to init_request (with initreq.h)
- Processes no longer killed when "process" field
changes, change takes effect after next respawn.
2.57b xx-Aug-1995
- Bugfix release for Debian and Slackware 3.0
2.57a 10-Jul-1995
- Fixed race condition init init.c wrt got_chld
- Fixed one-off for malloc in killall5.c
- Changed dowall.c
- Console code: no relink to /dev/systty on CTRL-ALT-DEL)
2.57 22-May-1995
- Changed a few things here and there, didn't
really document it :)
2.55 17-Jan-1995
- Added option to shutdown to run standalone.
2.54 12-Jan-1995
- Added GNU copyrigh to all *.[ch] files.
- added /etc/initscript
- reboot and halt now call shutdown in runlevels 1-5
- Can run from read-only root (CDROM)
2.53 10-Oct-1994
- Renamed pidof to killall5, updated all scripts to
use killall5 instead of kill -1 ....
- Rewrote scripts to use this, and some general changes.
- Added SysV command line compatibility to shutdown.
2.52 30-Aug-1994
- Added `powerfailnow' keyword, for when UPS battery is low.
- Updated `last'.
- Fixed utmp handling (wrt. CLEAN_UTMP)
TODO:
* Make last compatible with GNU/BSD (long options?)
* update powerd
* remote SIGPWR broadcast? in powerd? (with priv. port)
* remote shutdown
2.50 14-Feb-1994
- Ignores unknown command line arguments.
- Modelled more after the "real" sysVinit
- Lots of changes all over the place.
(like showing runlevel in "ps" listing, logging
runlevel into utmp file etc)
- now using "reliable" signals instead of V7 style.
- Updated all scripts. Examples are in two directories:
etc (normal) and etc-sysv (sysv style scripts).
- runlevel 0 = halt, 1 = single user, 6 = reboot.
- added support for serial console.
- updated Propaganda, manpages.
- added shutdown access control.
2.4 24-May-93
- Send out the official version into the world as
SysVinit-2.4.tar.z.
2.4g 15-May-93
- Changed init to really catch SIGPWR 'cause we
hooked up an UPS to the Linux machine. The
keyword for catching the TreeFingerSalute is
now "ctrlaltdel" instead of "power{wait,fail}".
2.4a 22-Apr-93
- Fixed last to reckognize BSD style wtmp logging.
- Changed init to write wtmp records that are
SysV compliant but are also reckognized by the
BSD last. Added a '+' option to the 'process'
field of inittab, for getties that want to do
their own utmp/wtmp housekeeping (kludge!).
- Now accepts a runlevel on the command line,
and reckognizes the 'auto' argument. (Sets the
environment variable AUTOBOOT to YES)
2.2.3 24-Mar-93
- Ripped out the 'leave' action. To difficult, and
unneeded.
- Going single user now kills _all_ processes.
- Added '-t secs' option to all commands.
- This version is stable enough to post.
2.2 02-Mar-93
- Made wait()'s asynchronous
- Changed whole thing to one big state machine
- Now using 'pseudo levels' # & * for SYSINIT & BOOT
- Added a new type of 'action', called leave. This
process will be executed when the system goes from a
runlevel specified in it's runlevel field to a
level that's not. Nice to bring down NFS and the like.
2.1 28-Jan-93
- Fixed a bug with 'boot' and 'once'.
- Check 'initdefault' for validity.
- Reckognizes "single" as command line argument.
- Retries execvp with 'sh -c exec ..' if command
is a shell script. (shouldn't execvp do this?)
- Added patches to use syslog if defined.
2.0 08-Dec-92
- Rewrote the code totally, so started with a new
version number.
- Dropped Minix support, this code now is Linux - specific.
- With TEST switch on, this init & telinit can
run standalone for test purposes.
1.3, 05-Jul-92
- Got a 386, so installed Linux. Added 'soft' reboot
to be default under linux. Fixed some typos.
1.2, 16-Jun-92
- Bugreport from Michael Haardt ; removed deadlock
and added 'waitpid' instead of 'wait' for SYSV.
1.1, 30-Apr-92
- Read manual wrong: there is no 'action' field called
process, but all entries are of type process. Every
'process' get exec'ed by /bin/sh -c 'exec command'.
- Rapidly respawning processes are caught in the act.
- _SYSV support is really Linux support,
done by poe@daimi.aau.dk on 25-Mar-92.
1.0, 01-Feb-92
- Initial version, very primitive for the Minix
operating system. Required some mods. to the
kernel.

56
doc/Install Normal file
View File

@ -0,0 +1,56 @@
README for the System V style init, version 2.86
init, shutdown, halt, reboot, wall, last, mesg, runlevel,
killall5, pidof, sulogin.
All programs, files and scripts in this package are covered by
the Gnu Public License, and copyrighted by me.
If you are not using Debian and the debianized package,
you will have to install the new init by hand. You should
be able to drop the binaries into a Slackware or Redhat
system, I think.
Here is a list of preferred directories to install the progs & manpages:
wall.1, last.1, mesg.1 /usr/man/man1
inittab.5, initscript.5 /usr/man/man5
init.8, halt.8, reboot.8,
shutdown.8, powerd.8,
killall5.8, pidof.8,
runlevel.8, sulogin.8 /usr/man/man8
init /sbin/init
inittab /etc/inittab
initscript.sample /etc/initscript.sample
telinit a link (with ln(1) ) to init, either
in /bin or in /sbin.
halt /sbin/halt
reboot a link to /sbin/halt in the same directory
killall5 /sbin/killall5
pidof a link to /sbin/killall5 in the same directory.
runlevel /sbin/runlevel
shutdown /sbin/shutdown.
wall /usr/bin/wall
mesg /usr/bin/mesg
last /usr/bin/last
sulogin /sbin/sulogin
bootlogd /sbin/bootlogd
utmpdump don't install, it's just a debug thingy.
If you already _have_ a "wall" in /bin (the SLS release had, for example)
do _not_ install this wall. Chances are that the wall you are already
using is linked to /bin/write. Either first _remove_ /bin/wall before
installing the new one, or don't install the new one at all.
You might want to create a file called "/etc/shutdown.allow". Read the
manual page on shutdown to find out more about this.
Running from a read-only file system (CDROM?):
o All communication to init goes through the FIFO /dev/initctl.
There should be no problem using a read-only root file system
IF you use a Linux kernel > 1.3.66. Older kernels don't allow
writing to a FIFO on a read-only file system.
Miquel van Smoorenburg <miquels@cistron.nl>

81
doc/Propaganda Normal file
View File

@ -0,0 +1,81 @@
Propaganda for version 2.58 of sysvinit & utilities
==================================================
NOTE: If you use a standard distribution like Slackware, Debian
or Redhat there probably is no need to upgrade. Installing sysvinit
is only for those that upgrade their system by hand or for people
that create Linux distributions.
Sysvinit is probably the most widely used init package for Linux.
Most distributions use it. sysvinit 2.4 is really a good package,
and it was not the need for bugfixes but the need for more features
that made me work on sysvinit again.
Sysvinit is now a debian package. Debian source packages are not
special in any way -- in fact you can just unpack and compile
it on any other Linux distribution.
There was a 2.50 release of sysvinit but that was not very popular-
some of the included scripts broke with certain shells and other
minor things like that. Unfortunately I was not able to fix this
at the time because I was abroad for some time. Therefore the
description below is a comparison of 2.4 and 2.58 (actually the
same blurb as from the 2.50 announce but updated).
Wrt 2.4, some of the code has been made simpler. Everything, from
halt to reboot to single user mode is now done by shell scripts
that are executed directly by init (from /etc/inittab), so shutdown
does not kill processes anymore and then calls reboot - it merely
does some wall's to the logged in users and then switches to
runlevel 0 (halt), 1 (single user) or 6 (reboot).
I have removed support for the old style scripts; the included
example scripts are the Debian GNU/Linux distribution scripts.
This does not mean that eg the Slackware scripts stop to work;
you can probably drop this init into Slackware 3.0 without problems.
Most people have an entry in inittab to run shutdown when CTRL-ALT-DEL
is pressed; a feature has been added to shutdown to check if a
authorized user is logged in on one of the consoles to see if a
shutdown is allowed. This can be configured with an access file.
Some other general changes:
- utility "runlevel" to read the current and previous runlevel from
/var/run/utmp (it's also shown on the command line if you do a "ps").
- unreckognized options are silently ignored (such as the infamous
"ro" - mount root file system read only).
- if the file /etc/initscript is present it will be used to launch
all programs that init starts (so that you can set a generic
umask, ulimit eg for ALL processes - see initscript.sample).
- A "sulogin" program added that always asks for the root
passsword before entering single user mode.
- A "-b" flag to init that starts a shell at boot time before
_any_ other processing.
- I moved /etc/fastboot to /fastboot - wonder what that's gonna break :)
- I even updated the manpages!
Right, now some boring stuff you already know since it's the same
as in the 2.4 release:
The sysvinit package includes
* a sysv compatible /sbin/init program
* a telinit program (er, just a link to /sbin/init) to change runlevels
* a featureful shutdown
* halt and reboot to assist shutdown
* a very forgiving last utility
* the wall & mesg programs (not installed by default)
* manpages for everything
The new sysv init can be found on:
tsx-11.mit.edu:/pub/linux/sources/sbin as sysvinit-2.58-1.tar.gz
sunsite.unc.edu:/pub/Linux/system/Daemons as sysvinit-2.58-1.tar.gz
It will be moved there in a few days, in the mean time it is
probably in the Incoming directory.
Mike. (02-Jan-1996)

19
doc/bootlogd.README Normal file
View File

@ -0,0 +1,19 @@
bootlogd: a way to capture all console output during bootup
in a logfile.
- bootlogd opens /dev/console and finds out what the real console is
with an ioctl() if TIOCCONS is available
- otherwise bootlogd tries to parse /proc/cmdline for console=
kernel command line arguments
- then opens the (most probable) real console
- allocates a pty pair
- redirects console I/O to the pty pair
- then goes in a loop reading from the pty, writing to the real
console and a logfile as soon as a r/w partition is available,
buffering in memory until then.
As soon as bootlogd exits or gets killed, the pty is closed and the
redirection will be automatically undone by the kernel. So that's
pretty safe.

14
doc/sysvinit-2.86.lsm Normal file
View File

@ -0,0 +1,14 @@
Begin3
Title: sysvinit and utilities
Version: 2.86
Entered-Date: 30JUL2004
Description: This is the Linux System V init.
This version can be compiled with glibc 2.0.6 and up.
Author: miquels@cistron.nl (Miquel van Smoorenburg)
Primary-Site: ftp.cistron.nl /pub/people/miquels/software
92K sysvinit-2.86.tar.gz
Alternate-Site: sunsite.unc.edu /pub/Linux/system/daemons/init
92K sysvinit-2.86.tar.gz
Copying-Policy: GPL
Keywords: init shutdown halt reboot
End

72
man/bootlogd.8 Normal file
View File

@ -0,0 +1,72 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH BOOTLOGD 8 "Jul 21, 2003" "" "Linux System Administrator's Manual"
.SH NAME
bootlogd \- record boot messages
.SH SYNOPSIS
.B /sbin/bootlogd
.RB [ \-c ]
.RB [ \-d ]
.RB [ \-r ]
.RB [ \-s ]
.RB [ \-v ]
.RB [ " -l logfile " ]
.RB [ " -p pidfile " ]
.SH DESCRIPTION
\fBBootlogd\fP runs in the background and copies all strings sent to the
\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
the messages will be kept in memory until it is.
.SH OPTIONS
.IP \fB\-d\fP
Do not fork and run in the background.
.IP \fB\-c\fP
Attempt to write to the logfile even if it does not yet exist.
Without this option,
.B bootlogd
will wait for the logfile to appear before attempting to write to it.
This behavior prevents bootlogd from creating logfiles under mount points.
.IP \fB\-r\fP
If there is an existing logfile called \fIlogfile\fP rename it to
\fIlogfile~\fP unless \fIlogfile~\fP already exists.
.IP \fB\-s\fP
Ensure that the data is written to the file after each line by calling
.BR fdatasync (3).
This will slow down a
.BR fsck (8)
process running in parallel.
.IP \fB\-v\fP
Show version.
.IP "\fB\-l\fP \fIlogfile\fP"
Log to this logfile. The default is \fI/var/log/boot\fP.
.IP "\fB\-p\fP \fIpidfile\fP"
Put process-id in this file. The default is no pidfile.
.SH BUGS
Bootlogd works by redirecting the console output from the console device.
(Consequently \fBbootlogd\fP requires PTY support in the kernel configuration.)
It copies that output to the real console device and to a log file.
There is no standard way of ascertaining the real console device
if you have a new-style \fI/dev/console\fP device (major 5, minor 1)
so \fBbootlogd\fP parses the kernel command line looking for
\fBconsole=...\fP lines and deduces the real console device from that.
If that syntax is ever changed by the kernel, or a console type is used that
\fBbootlogd\fP does not know about then \fBbootlogd\fP will not work.
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl
.SH "SEE ALSO"
.BR dmesg (8), fdatasync (3).

52
man/bootlogd.8.todo Normal file
View File

@ -0,0 +1,52 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-1999 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH BOOTLOGD 8 "Aug 24, 1999" "" "Linux System Administrator's Manual"
.SH NAME
bootlogd \- record boot messages
.SH SYNOPSIS
.B /sbin/bootlogd
.RB [ \-d ]
.RB [ \-r ]
.RB [ \-v ]
.RB [ " -l logfile " ]
.RB [ " -p pidfile " ]
.SH DESCRIPTION
\fBBootlogd\fP runs in the background and copies all strings sent to the
\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
the messages will be buffered in-memory until it is.
.SH OPTIONS
.IP \fB\-d\fP
Do not fork and run in the background.
.IP \fB\-r\fP
If there is an existing logfile called \fIlogfile\fP rename it to
\fIlogfile~\fP unless \fIlogfile~\fP already exists.
.IP \fB\-v\fP
Show version.
.IP \fB\-l logfile\fP
Log to this logfile. The default is \fI/var/log/boot.log\fP.
.IP \fB\-p pidfile\fP
Put process-id in this file. The default is no pidfile.
.SH NOTES
There is no standard way to find out the real console device if you have
a new-style \fI/dev/console\fP device (major 5, minor 1). \fBBootlogd\fP
might have some difficulties to do this, especially under very old
or very new kernels.
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl
.SH "SEE ALSO"
.BR dmesg (8)

120
man/halt.8 Normal file
View File

@ -0,0 +1,120 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.\"{{{}}}
.\"{{{ Title
.TH HALT 8 "Nov 6, 2001" "" "Linux System Administrator's Manual"
.\"}}}
.\"{{{ Name
.SH NAME
halt, reboot, poweroff \- stop the system.
.\"}}}
.\"{{{ Synopsis
.SH SYNOPSIS
.B /sbin/halt
.RB [ \-n ]
.RB [ \-w ]
.RB [ \-d ]
.RB [ \-f ]
.RB [ \-i ]
.RB [ \-p ]
.RB [ \-h ]
.br
.B /sbin/reboot
.RB [ \-n ]
.RB [ \-w ]
.RB [ \-d ]
.RB [ \-f ]
.RB [ \-i ]
.br
.B /sbin/poweroff
.RB [ \-n ]
.RB [ \-w ]
.RB [ \-d ]
.RB [ \-f ]
.RB [ \-i ]
.RB [ \-h ]
.\"}}}
.\"{{{ Description
.SH DESCRIPTION
\fBHalt\fP notes that the system is being brought down in the file
\fI/var/log/wtmp\fP, and then either tells the kernel to halt, reboot or
power-off the system.
.PP
If \fBhalt\fP or \fBreboot\fP is called when the system is
\fInot\fP in runlevel \fB0\fP or \fB6\fP, in other words when it's running
normally, \fBshutdown\fP will be invoked instead (with the \fB-h\fP
or \fB-r\fP flag). For more info see the \fBshutdown\fP(8)
manpage.
.PP
The rest of this manpage describes the behaviour in runlevels 0
and 6, that is when the systems shutdown scripts are being run.
.\"}}}
.\"{{{ Options
.SH OPTIONS
.IP \fB\-n\fP
Don't sync before reboot or halt. Note that the kernel and storage
drivers may still sync.
.IP \fB\-w\fP
Don't actually reboot or halt but only write the wtmp record
(in the \fI/var/log/wtmp\fP file).
.IP \fB\-d\fP
Don't write the wtmp record. The \fB\-n\fP flag implies \fB\-d\fP.
.IP \fB\-f\fP
Force halt or reboot, don't call \fBshutdown\fP(8).
.IP \fB\-i\fP
Shut down all network interfaces just before halt or reboot.
.IP \fB\-h\fP
Put all hard drives on the system in stand-by mode just before halt or power-off.
.IP \fB\-p\fP
When halting the system, switch off the power. This is the default when halt is
called as \fBpoweroff\fP.
.\"}}}
.\"{{{ Diagnostics
.SH DIAGNOSTICS
If you're not the superuser, you will get the message `must be superuser'.
.\"}}}
.\"{{{ Notes
.SH NOTES
Under older \fBsysvinit\fP releases , \fBreboot\fP and \fBhalt\fP should
never be called directly. From release 2.74 on \fBhalt\fP and \fBreboot\fP
invoke \fBshutdown\fP(8) if the system is not in runlevel 0 or 6. This
means that if \fBhalt\fP or \fBreboot\fP cannot find out the current
runlevel (for example, when \fI/var/run/utmp\fP hasn't been initialized
correctly) \fBshutdown\fP will be called, which might not be what you want.
Use the \fB-f\fP flag if you want to do a hard \fBhalt\fP or \fBreboot\fP.
.PP
The \fB-h\fP flag puts all hard disks in standby mode just before halt
or power-off. Right now this is only implemented for IDE drives. A side
effect of putting the drive in stand-by mode is that the write cache
on the disk is flushed. This is important for IDE drives, since the
kernel doesn't flush the write cache itself before power-off.
.PP
The \fBhalt\fP program uses /proc/ide/hd* to find all IDE disk devices,
which means that \fI/proc\fP needs to be mounted when \fBhalt\fP or
\fBpoweroff\fP is called or the \fB-h\fP switch will do nothing.
.PP
.\"}}}
.\"{{{ Author
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl
.\"}}}
.\"{{{ See also
.SH "SEE ALSO"
.BR shutdown (8),
.BR init (8)
.\"}}}

313
man/init.8 Normal file
View File

@ -0,0 +1,313 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.\"{{{}}}
.\"{{{ Title
.TH INIT 8 "29 Jul 2004" "" "Linux System Administrator's Manual"
.\"}}}
.\"{{{ Name
.SH NAME
init, telinit \- process control initialization
.\"}}}
.\"{{{ Synopsis
.SH SYNOPSIS
.B /sbin/init
.RB [ " -a " ]
.RB [ " -s " ]
.RB [ " -b " ]
[ \fB\-z\fP \fIxxx\fP ]
.RB [ " 0123456Ss " ]
.br
.B /sbin/telinit
[ \fB\-t\fP \fISECONDS\fP ]
.RB [ " 0123456sSQqabcUu " ]
.br
.B /sbin/telinit
[ \fB\-e\fP \fIVAR\fP[\fB=\fP\fIVAL\fP] ]
.\"}}}
.\"{{{ Description
.SH DESCRIPTION
.\"{{{ init
.SS Init
.B Init
is the parent of all processes. Its primary role is to create processes
from a script stored in the file \fB/etc/inittab\fP (see
\fIinittab\fP(5)). This file usually has entries which cause \fBinit\fP
to spawn \fBgetty\fPs on each line that users can log in. It also
controls autonomous processes required by any particular system.
.PP
.\"{{{ Runlevels
.SH RUNLEVELS
A \fIrunlevel\fP is a software configuration of the system which allows
only a selected group of processes to exist. The processes spawned by
\fBinit\fP for each of these runlevels are defined in the
\fB/etc/inittab\fP file. \fBInit\fP can be in one of eight runlevels:
\fB0\(en6\fP and \fBS\fP or \fBs\fP. The runlevel is
changed by having a privileged user run \fBtelinit\fP, which sends
appropriate signals to \fBinit\fP, telling it which runlevel to change
to.
.PP
Runlevels \fB0\fP, \fB1\fP, and \fB6\fP are reserved. Runlevel 0 is used to
halt the system, runlevel 6 is used to reboot the system, and runlevel
1 is used to get the system down into single user mode. Runlevel \fBS\fP
is not really meant to be used directly, but more for the scripts that are
executed when entering runlevel 1. For more information on this,
see the manpages for \fBshutdown\fP(8) and \fBinittab\fP(5).
.PP
Runlevels 7-9 are also valid, though not really documented. This is
because "traditional" Unix variants don't use them.
In case you're curious, runlevels \fIS\fP and \fIs\fP are in fact the same.
Internally they are aliases for the same runlevel.
.\"}}}
.PP
.SH BOOTING
After \fBinit\fP is invoked as the last step of the kernel boot sequence,
it looks for the file \fB/etc/inittab\fP to see if there is an entry of the
type \fBinitdefault\fP (see \fIinittab\fP(5)). The \fBinitdefault\fP entry
determines the initial runlevel of the system. If there is no such
entry (or no \fB/etc/inittab\fP at all), a runlevel must be
entered at the system console.
.PP
Runlevel \fBS\fP or \fBs\fP bring the system to single user mode
and do not require an \fB/etc/inittab\fP file. In single user mode,
\fB/sbin/sulogin\fP is invoked on \fB/dev/console\fP.
.PP
When entering single user mode, \fBinit\fP initializes the consoles
\fBstty\fP settings to sane values. Clocal mode is set. Hardware
speed and handshaking are not changed.
.PP
When entering a multi-user mode for the first time, \fBinit\fP performs the
\fBboot\fP and \fBbootwait\fP entries to allow file systems to be
mounted before users can log in. Then all entries matching the runlevel
are processed.
.PP
When starting a new process, \fBinit\fP first checks whether the file
\fI/etc/initscript\fP exists. If it does, it uses this script to
start the process.
.PP
Each time a child terminates, \fBinit\fP records the fact and the reason
it died in \fB/var/run/utmp\fP and \fB/var/log/wtmp\fP,
provided that these files exist.
.SH CHANGING RUNLEVELS
After it has spawned all of the processes specified, \fBinit\fP waits
for one of its descendant processes to die, a powerfail signal, or until
it is signaled by \fBtelinit\fP to change the system's runlevel.
When one of the above three conditions occurs, it re-examines
the \fB/etc/inittab\fP file. New entries can be added to this file at
any time. However, \fBinit\fP still waits for one of the above three
conditions to occur. To provide for an instantaneous response, the
\fBtelinit Q\fP or \fBq\fP command can wake up \fBinit\fP to re-examine the
\fB/etc/inittab\fP file.
.PP
If \fBinit\fP is not in single user mode and receives a powerfail
signal (SIGPWR), it reads the file \fB/etc/powerstatus\fP. It then starts
a command based on the contents of this file:
.IP F(AIL)
Power is failing, UPS is providing the power. Execute the \fBpowerwait\fP
and \fBpowerfail\fP entries.
.IP O(K)
The power has been restored, execute the \fBpowerokwait\fP entries.
.IP L(OW)
The power is failing and the UPS has a low battery. Execute the
\fBpowerfailnow\fP entries.
.PP
If /etc/powerstatus doesn't exist or contains anything else then the
letters \fBF\fP, \fBO\fP or \fBL\fP, init will behave as if it has read
the letter \fBF\fP.
.PP
Usage of \fBSIGPWR\fP and \fB/etc/powerstatus\fP is discouraged. Someone
wanting to interact with \fBinit\fP should use the \fB/dev/initctl\fP
control channel - see the source code of the \fBsysvinit\fP package
for more documentation about this.
.PP
When \fBinit\fP is requested to change the runlevel, it sends the
warning signal \s-1\fBSIGTERM\fP\s0 to all processes that are undefined
in the new runlevel. It then waits 5 seconds before forcibly
terminating these processes via the \s-1\fBSIGKILL\fP\s0 signal.
Note that \fBinit\fP assumes that all these processes (and their
descendants) remain in the same process group which \fBinit\fP
originally created for them. If any process changes its process group
affiliation it will not receive these signals. Such processes need to
be terminated separately.
.\"}}}
.\"{{{ telinit
.SH TELINIT
\fB/sbin/telinit\fP is linked to \fB/sbin/init\fP. It takes a
one-character argument and signals \fBinit\fP to perform the appropriate
action. The following arguments serve as directives to
\fBtelinit\fP:
.IP "\fB0\fP,\fB1\fP,\fB2\fP,\fB3\fP,\fB4\fP,\fB5\fP or \fB6\fP"
tell \fBinit\fP to switch to the specified run level.
.IP \fBa\fP,\fBb\fP,\fBc\fP
tell \fBinit\fP to process only those \fB/etc/inittab\fP file
entries having runlevel \fBa\fP,\fBb\fP or \fBc\fP.
.IP "\fBQ\fP or \fBq\fP"
tell \fBinit\fP to re-examine the \fB/etc/inittab\fP file.
.IP "\fBS\fP or \fBs\fP"
tell \fBinit\fP to switch to single user mode.
.IP "\fBU\fP or \fBu\fP"
tell \fBinit\fP to re-execute itself (preserving the state). No re-examining of
\fB/etc/inittab\fP file happens. Run level should be one of
\fBSs0123456\fP
otherwise request would be silently ignored.
.PP
\fBtelinit\fP can tell \fBinit\fP how long it should wait
between sending processes the SIGTERM and SIGKILL signals. The default
is 5 seconds, but this can be changed with the \fB-t\fP option.
.PP
\fBtelinit -e\fP tells \fBinit\fP to change the environment
for processes it spawns.
The argument of \fB-e\fP is either of the form \fIVAR\fP=\fIVAL\fP
which sets variable \fIVAR\fP to value \fIVAL\fP,
or of the form \fIVAR\fP
(without an equality sign)
which unsets variable \fIVAR\fP.
.PP
\fBtelinit\fP can be invoked only by users with appropriate
privileges.
.PP
The \fBinit\fP binary checks if it is \fBinit\fP or \fBtelinit\fP by looking
at its \fIprocess id\fP; the real \fBinit\fP's process id is always \fB1\fP.
From this it follows that instead of calling \fBtelinit\fP one can also
just use \fBinit\fP instead as a shortcut.
.\"}}}
.\"}}}
.SH ENVIRONMENT
\fBInit\fP sets the following environment variables for all its children:
.IP \fBPATH\fP
\fI/bin:/usr/bin:/sbin:/usr/sbin\fP
.IP \fBINIT_VERSION\fP
As the name says. Useful to determine if a script runs directly from \fBinit\fP.
.IP \fBRUNLEVEL\fP
The current system runlevel.
.IP \fBPREVLEVEL\fP
The previous runlevel (useful after a runlevel switch).
.IP \fBCONSOLE\fP
The system console. This is really inherited from the kernel; however
if it is not set \fBinit\fP will set it to \fB/dev/console\fP by default.
.SH BOOTFLAGS
It is possible to pass a number of flags to \fBinit\fP from the
boot monitor (eg. LILO). \fBInit\fP accepts the following flags:
.TP 0.5i
.B -s, S, single
Single user mode boot. In this mode \fI/etc/inittab\fP is
examined and the bootup rc scripts are usually run before
the single user mode shell is started.
.PP
.TP 0.5i
.B 1-5
Runlevel to boot into.
.PP
.TP 0.5i
.B -b, emergency
Boot directly into a single user shell without running any
other startup scripts.
.PP
.TP 0.5i
.B -a, auto
The LILO boot loader adds the word "auto" to the command line if it
booted the kernel with the default command line (without user intervention).
If this is found \fBinit\fP sets the "AUTOBOOT" environment
variable to "yes". Note that you cannot use this for any security
measures - of course the user could specify "auto" or \-a on the
command line manually.
.PP
.TP 0.5i
.BI "-z " xxx
The argument to \fB-z\fP is ignored. You can use this to expand the command
line a bit, so that it takes some more space on the stack. \fBInit\fP
can then manipulate the command line so that \fBps\fP(1) shows
the current runlevel.
.PP
.SH INTERFACE
Init listens on a \fIfifo\fP in /dev, \fI/dev/initctl\fP, for messages.
\fBTelinit\fP uses this to communicate with init. The interface is not
very well documented or finished. Those interested should study the
\fIinitreq.h\fP file in the \fIsrc/\fP subdirectory of the \fBinit\fP
source code tar archive.
.SH SIGNALS
Init reacts to several signals:
.TP 0.5i
.B SIGHUP
Has the same effect as \fBtelinit q\fP.
.PP
.TP 0.5i
.B SIGUSR1
On receipt of this signals, init closes and re-opens its control fifo,
\fB/dev/initctl\fP. Useful for bootscripts when /dev is remounted.
.TP 0.5i
.B SIGINT
Normally the kernel sends this signal to init when CTRL-ALT-DEL is
pressed. It activates the \fIctrlaltdel\fP action.
.TP 0.5i
.B SIGWINCH
The kernel sends this signal when the \fIKeyboardSignal\fP key is hit.
It activates the \fIkbrequest\fP action.
\"{{{ Conforming to
.SH CONFORMING TO
\fBInit\fP is compatible with the System V init. It works closely
together with the scripts in the directories
\fI/etc/init.d\fP and \fI/etc/rc{runlevel}.d\fP.
If your system uses this convention, there should be a \fIREADME\fP
file in the directory \fI/etc/init.d\fP explaining how these scripts work.
.\"}}}
.\"{{{ Files
.SH FILES
.nf
/etc/inittab
/etc/initscript
/dev/console
/var/run/utmp
/var/log/wtmp
/dev/initctl
.fi
.\"}}}
.\"{{{ Warnings
.SH WARNINGS
\fBInit\fP assumes that processes and descendants of processes
remain in the same process group which was originally created
for them. If the processes change their group, \fBinit\fP can't
kill them and you may end up with two processes reading from one
terminal line.
.\"}}}
.\"{{{ Diagnostics
.SH DIAGNOSTICS
If \fBinit\fP finds that it is continuously respawning an entry
more than 10 times in 2 minutes, it will assume that there is an error
in the command string, generate an error message on the system console,
and refuse to respawn this entry until either 5 minutes has elapsed or
it receives a signal. This prevents it from eating up system resources
when someone makes a typographical error in the \fB/etc/inittab\fP file
or the program for the entry is removed.
.\"}}}
.\"{{{ Author
.SH AUTHOR
Miquel van Smoorenburg (miquels@cistron.nl), initial manual
page by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
.\"}}}
.\"{{{ See also
.SH "SEE ALSO"
.BR getty (1),
.BR login (1),
.BR sh (1),
.BR runlevel (8),
.BR shutdown(8),
.BR kill (1),
.BR inittab (5),
.BR initscript (5),
.BR utmp (5)
.\"}}}

72
man/initscript.5 Normal file
View File

@ -0,0 +1,72 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH INITSCRIPT 5 "July 10, 2003" "" "Linux System Administrator's Manual"
.SH NAME
initscript \- script that executes inittab commands.
.SH SYNOPSIS
/bin/sh /etc/initscript id runlevels action process
.SH DESCRIPTION
When the shell script \fI/etc/initscript\fP is present, \fBinit\fP
will use it to execute the commands from \fIinittab\fP.
This script can be used to set things like \fBulimit\fP and
\fBumask\fP default values for every process.
.SH EXAMPLES
This is a sample initscript, which might be installed on your
system as \fI/etc/initscript.sample\fP.
.RS
.sp
.nf
.ne 7
#
# initscript Executed by init(8) for every program it
# wants to spawn like this:
#
# /bin/sh /etc/initscript <id> <level> <action> <process>
#
# Set umask to safe level, and enable core dumps.
umask 022
ulimit -c 2097151
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Increase the hard file descriptor limit for all processes
# to 8192. The soft limit is still 1024, but any unprivileged
# process can increase its soft limit up to the hard limit
# with "ulimit -Sn xxx" (needs a 2.2.13 or later Linux kernel).
ulimit -Hn 8192
# Execute the program.
eval exec "$4"
.sp
.RE
.SH NOTES
This script is not meant as startup script for daemons or somesuch.
It has nothing to do with a \fIrc.local\fP style script. It's just
a handler for things executed from \fB/etc/inittab\fP. Experimenting
with this can make your system un(re)bootable.
.RE
.SH FILES
/etc/inittab,
/etc/initscript.
.SH AUTHOR
Miquel van Smoorenburg ,<miquels@cistron.nl>
.SH "SEE ALSO"
init(8), inittab(5).

265
man/inittab.5 Normal file
View File

@ -0,0 +1,265 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.\"{{{}}}
.\"{{{ Title
.TH INITTAB 5 "Dec 4, 2001" "" "Linux System Administrator's Manual"
.\"}}}
.\"{{{ Name
.SH NAME
inittab \- format of the inittab file used by the sysv-compatible init
process
.\"}}}
.\"{{{ Description
.SH DESCRIPTION
The \fBinittab\fP file describes which processes are started at bootup and
during normal operation (e.g.\& /etc/init.d/boot, /etc/init.d/rc, gettys...).
.BR Init (8)
distinguishes multiple \fIrunlevels\fP, each of which can have its own set of
processes that are started. Valid runlevels are \fB0\fP\-\fB6\fP plus
\fBA\fP, \fBB\fP, and \fBC\fP for \fBondemand\fP entries. An entry in the
\fBinittab\fP file has the following format:
.RS
.sp
\fIid\fP:\fIrunlevels\fP:\fIaction\fP:\fIprocess\fP
.sp
.RE
Lines beginning with `#' are ignored.
.\"{{{ id
.IP \fIid\fP
is a unique sequence of 1-4 characters which identifies an entry in
.B inittab
(for versions of sysvinit compiled with the \fIold\fP libc5 (< 5.2.18) or
a.out libraries the limit is 2 characters).
.sp
Note: traditionally, for getty and other login processes, the value of the
\fIid\fP field is kept the same as the suffix of the corresponding tty, e.g.\&
\fB1\fP for \fBtty1\fP. Some ancient login accounting programs might
expect this, though I can't think of any.
.\"}}}
.\"{{{ runlevels
.IP \fIrunlevels\fP
lists the runlevels for which the specified action should be taken.
.\"}}}
.\"{{{ action
.IP \fIaction\fP
describes which action should be taken.
.\"}}}
.\"{{{ process
.IP \fIprocess\fP
specifies the process to be executed. If the process field starts with
a `+' character,
.B init
will not do utmp and wtmp accounting for that process. This is needed for
gettys that insist on doing their own utmp/wtmp housekeeping. This is also
a historic bug.
.\"}}}
.PP
The \fIrunlevels\fP field may contain multiple characters for different
runlevels. For example, \fB123\fP specifies that the process should be
started in runlevels 1, 2, and 3.
The \fIrunlevels\fP for \fBondemand\fP entries may contain an \fBA\fP,
\fBB\fP, or \fBC\fP. The \fIrunlevels\fP field of \fBsysinit\fP,
\fBboot\fP, and \fBbootwait\fP entries are ignored.
.PP
When the system runlevel is changed, any running processes that are not
specified for the new runlevel are killed, first with \s-2SIGTERM\s0,
then with \s-2SIGKILL\s0.
.PP
Valid actions for the \fIaction\fP field are:
.\"{{{ respawn
.IP \fBrespawn\fP
The process will be restarted whenever it terminates (e.g.\& getty).
.\"}}}
.\"{{{ wait
.IP \fBwait\fP
The process will be started once when the specified runlevel is entered and
.B init
will wait for its termination.
.\"}}}
.\"{{{ once
.IP \fBonce\fP
The process will be executed once when the specified runlevel is
entered.
.\"}}}
.\"{{{ boot
.IP \fBboot\fP
The process will be executed during system boot. The \fIrunlevels\fP
field is ignored.
.\"}}}
.\"{{{ bootwait
.IP \fBbootwait\fP
The process will be executed during system boot, while
.B init
waits for its termination (e.g.\& /etc/rc).
The \fIrunlevels\fP field is ignored.
.\"}}}
.\"{{{ off
.IP \fBoff\fP
This does nothing.
.\"}}}
.\"{{{ ondemand
.IP \fBondemand\fP
A process marked with an \fBondemand\fP runlevel will be executed
whenever the specified \fBondemand\fP runlevel is called. However, no
runlevel change will occur (\fBondemand\fP runlevels are `a', `b',
and `c').
.\"}}}
.\"{{{ initdefault
.IP \fBinitdefault\fP
An \fBinitdefault\fP entry specifies the runlevel which should be
entered after system boot. If none exists,
.B init
will ask for a runlevel on the console. The \fIprocess\fP field is ignored.
.\"}}}
.\"{{{ sysinit
.IP \fBsysinit\fP
The process will be executed during system boot. It will be
executed before any \fBboot\fP or \fB bootwait\fP entries.
The \fIrunlevels\fP field is ignored.
.\"}}}
.\"{{{ powerwait
.IP \fBpowerwait\fP
The process will be executed when the power goes down. Init is usually
informed about this by a process talking to a UPS connected to the computer.
\fBInit\fP will wait for the process to finish before continuing.
.\"}}}
.\"{{{ powerfail
.IP \fBpowerfail\fP
As for \fBpowerwait\fP, except that \fBinit\fP does not wait for the process's
completion.
.\"}}}
.\"{{{ powerokwait
.IP \fBpowerokwait\fP
This process will be executed as soon as \fBinit\fP is informed that the
power has been restored.
.\"}}}
.\"{{{ powerfailnow
.IP \fBpowerfailnow\fP
This process will be executed when \fBinit\fP is told that the battery of
the external UPS is almost empty and the power is failing (provided that the
external UPS and the monitoring process are able to detect this condition).
.\"}}}
.\"{{{ ctrlaltdel
.IP \fBctrlaltdel\fP
The process will be executed when \fBinit\fP receives the SIGINT signal.
This means that someone on the system console has pressed the
\fBCTRL\-ALT\-DEL\fP key combination. Typically one wants to execute some
sort of \fBshutdown\fP either to get into single\-user level or to
reboot the machine.
.\"}}}
.\"{{{ kbrequest
.IP \fBkbrequest\fP
The process will be executed when \fBinit\fP receives a signal from the
keyboard handler that a special key combination was pressed on the
console keyboard.
.sp
The documentation for this function is not complete yet; more documentation
can be found in the kbd-x.xx packages (most recent was kbd-0.94 at
the time of this writing). Basically you want to map some keyboard
combination to the "KeyboardSignal" action. For example, to map Alt-Uparrow
for this purpose use the following in your keymaps file:
.RS
.sp
alt keycode 103 = KeyboardSignal
.sp
.RE
.\"}}}
.\"}}}
.\"{{{ Examples
.SH EXAMPLES
This is an example of a inittab which resembles the old Linux inittab:
.RS
.sp
.nf
.ne 7
# inittab for linux
id:1:initdefault:
rc::bootwait:/etc/rc
1:1:respawn:/etc/getty 9600 tty1
2:1:respawn:/etc/getty 9600 tty2
3:1:respawn:/etc/getty 9600 tty3
4:1:respawn:/etc/getty 9600 tty4
.fi
.sp
.RE
This inittab file executes \fB/etc/rc\fP during boot and starts gettys
on tty1\-tty4.
.PP
A more elaborate \fBinittab\fP with different runlevels (see the comments
inside):
.RS
.sp
.nf
.ne 19
# Level to run in
id:2:initdefault:
# Boot-time system configuration/initialization script.
si::sysinit:/etc/init.d/rcS
# What to do in single-user mode.
~:S:wait:/sbin/sulogin
# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# What to do at the "3 finger salute".
ca::ctrlaltdel:/sbin/shutdown -t1 -h now
# Runlevel 2,3: getty on virtual consoles
# Runlevel 3: getty on terminal (ttyS0) and modem (ttyS1)
1:23:respawn:/sbin/getty tty1 VC linux
2:23:respawn:/sbin/getty tty2 VC linux
3:23:respawn:/sbin/getty tty3 VC linux
4:23:respawn:/sbin/getty tty4 VC linux
S0:3:respawn:/sbin/getty -L 9600 ttyS0 vt320
S1:3:respawn:/sbin/mgetty -x0 -D ttyS1
.fi
.sp
.RE
.\"}}}
.\"{{{ Files
.SH FILES
/etc/inittab
.\"}}}
.\"{{{ Author
.SH AUTHOR
\fBInit\fP was written by Miquel van Smoorenburg
(miquels@cistron.nl). This manual page was written by
Sebastian Lederer (lederer@francium.informatik.uni-bonn.de) and modified
by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
.\"}}}
.\"{{{ See also
.SH "SEE ALSO"
.BR init (8),
.BR telinit (8)
.\"}}}

49
man/killall5.8 Normal file
View File

@ -0,0 +1,49 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH KILLALL5 8 "04 Nov 2003" "" "Linux System Administrator's Manual"
.SH NAME
killall5 -- send a signal to all processes.
.SH SYNOPSIS
.B killall5
.RB -signalnumber
.RB [ \-o
.IR omitpid ]
.RB [ \-o
.IR omitpid.. ]
.SH DESCRIPTION
.B killall5
is the SystemV killall command. It sends a signal to all processes except
kernel threads and the processes in its own session, so it won't kill
the shell that is running the script it was called from. Its primary
(only) use is in the \fBrc\fP scripts found in the /etc/init.d directory.
.SH OPTIONS
.IP "-o \fIomitpid\fP"
Tells \fIkillall5\fP to omit processes with that process id.
.SH NOTES
\fIkillall5\fP can also be invoked as pidof, which is simply a
(symbolic) link to the \fIkillall5\fP program.
.SH EXIT STATUS
The program return zero if it killed processes. It return 2 if no
process were killed, and 1 if it was unable to find any processes
(/proc/ is missing).
.SH SEE ALSO
.BR halt (8),
.BR reboot (8),
.BR pidof (8)
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl

122
man/last.1 Normal file
View File

@ -0,0 +1,122 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.\"{{{}}}
.\"{{{ Title
.TH LAST,LASTB 1 "Jul 31, 2004" "" "Linux System Administrator's Manual"
.\"}}}
.\"{{{ Name
.SH NAME
last, lastb \- show listing of last logged in users
.\"}}}
.\"{{{ Synopsis
.SH SYNOPSIS
.B last
.RB [ \-R ]
.RB [ \-\fInum\fP ]
.RB "[ \-\fBn\fP \fInum\fP ]"
.RB [ \-adFiox ]
.RB "[ \-\fBf\fP \fIfile\fP ]"
.RB "[ \-\fBt\fP \fIYYYYMMDDHHMMSS\fP ]"
.RI [ name... ]
.RI [ tty... ]
.br
.B lastb
.RB [ \-R ]
.RB [ \-\fInum\fP ]
.RB "[ \-\fBn\fP \fInum\fP ]"
.RB "[ \-\fBf\fP \fIfile\fP ]"
.RB [ \-adFiox ]
.RI [ name... ]
.RI [ tty... ]
.\"}}}
.\"{{{ Description
.SH DESCRIPTION
.B Last
searches back through the file \fB/var/log/wtmp\fP (or the file
designated by the \fB\-f\fP flag) and displays a list of all
users logged in (and out) since that file was created. Names of users
and tty's can be given, in which case \fBlast\fP will show only those entries
matching the arguments. Names of ttys can be abbreviated, thus \fBlast
0\fP is the same as \fBlast tty0\fP.
.PP
When \fBlast\fP catches a \s-2SIGINT\s0 signal (generated by the interrupt key,
usually control-C) or a \s-2SIGQUIT\s0 signal (generated by the quit key,
usually control-\e), \fBlast\fP will show how far it has searched through the
file; in the case of the \s-2SIGINT\s0 signal \fBlast\fP will then terminate.
.PP
The pseudo user \fBreboot\fP logs in each time the system is rebooted.
Thus \fBlast reboot\fP will show a log of all reboots since the log file
was created.
.PP
\fBLastb\fP is the same as \fBlast\fP, except that by default it shows a log
of the file \fB/var/log/btmp\fP, which contains all the bad login attempts.
.\"}}}
.\"{{{ Options
.SH OPTIONS
.IP "\fB\-f\fP \fIfile\fP"
Tells \fBlast\fP to use a specific file instead of \fB/var/log/wtmp\fP.
.IP \fB\-\fP\fInum\fP
This is a count telling \fBlast\fP how many lines to show.
.IP "\fB\-n\fP \fInum\fP"
The same.
.IP "\fB\-t\fP \fIYYYYMMDDHHMMSS\fP"
Display the state of logins as of the specified time. This is
useful, e.g., to determine easily who was logged in at a particular
time -- specify that time with \fB\-t\fP and look for "still logged
in".
.IP \fB\-R\fP
Suppresses the display of the hostname field.
.IP \fB\-a\fP
Display the hostname in the last column. Useful in combination
with the next flag.
.IP \fB\-d\fP
For non-local logins, Linux stores not only the host name of the remote
host but its IP number as well. This option translates the IP number
back into a hostname.
.IP \fB\-F\fP
Print full login and logout times and dates.
.IP \fB\-i\fP
This option is like \fB-d\fP in that it displays the IP number of the remote
host, but it displays the IP number in numbers-and-dots notation.
.IP \fB\-o\fP
Read an old-type wtmp file (written by linux-libc5 applications).
.IP \fB\-x\fP
Display the system shutdown entries and run level changes.
.\"}}}
.SH NOTES
The files \fIwtmp\fP and \fIbtmp\fP might not be found. The system only
logs information in these files if they are present. This is a local
configuration issue. If you want the files to be used, they can be
created with a simple \fBtouch\fP(1) command (for example,
\fItouch /var/log/wtmp\fP).
.\"{{{ Files
.SH FILES
/var/log/wtmp
.br
/var/log/btmp
.\"}}}
.\"{{{ Author
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl
.\"}}}
.\"{{{ See also
.SH "SEE ALSO"
.BR shutdown (8),
.BR login (1),
.BR init (8)
.\"}}}

1
man/lastb.1 Normal file
View File

@ -0,0 +1 @@
.so man1/last.1

61
man/mesg.1 Normal file
View File

@ -0,0 +1,61 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.\"{{{}}}
.\"{{{ Title
.TH MESG 1 "Feb 26, 2001" "" "Linux User's Manual"
.\"}}}
.\"{{{ Name
.SH NAME
mesg \- control write access to your terminal
.\"}}}
.\"{{{ Synopsis
.SH SYNOPSIS
.B mesg
.RB [ y | n ]
.\"}}}
.\"{{{ Description
.SH DESCRIPTION
.B Mesg
controls the access to your terminal by others. It's typically used to
allow or disallow other users to write to your terminal (see \fBwrite\fP(1)).
.\"}}}
.\"{{{ Options
.SH OPTIONS
.IP \fBy\fP
Allow write access to your terminal.
.IP \fBn\fP
Disallow write access to your terminal.
.PP
If no option is given, \fBmesg\fP prints out the current access state of your
terminal.
.\"}}}
.\"{{{ Notes
.SH NOTES
\fBMesg\fP assumes that its standard input is connected to your
terminal. That also means that if you are logged in multiple times,
you can get/set the mesg status of other sessions by using redirection.
For example "mesg n < /dev/pts/46".
.SH AUTHOR
Miquel van Smoorenburg (miquels@cistron.nl)
.\"}}}
.\"{{{ See also
.SH "SEE ALSO"
.BR talk (1),
.BR write (1),
.BR wall (1)
.\"}}}

54
man/mountpoint.1 Normal file
View File

@ -0,0 +1,54 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH MOUNTPOINT 1 "Mar 15, 2004" "" "Linux System Administrator's Manual"
.SH NAME
mountpoint \- see if a directory is a mountpoint
.SH SYNOPSIS
.B /bin/mountpoint
.RB [ \-q ]
.RB [ \-d ]
.I /path/to/directory
.br
.B /bin/mountpoint
.RB \-x
.I /dev/device
.SH DESCRIPTION
\fBMountpoint\fP checks if the directory is a mountpoint.
.SH OPTIONS
.IP \fB\-q\fP
Be quiet - don't print anything.
.IP \fB\-d\fP
Print major/minor device number of the filesystem on stdout.
.IP \fB\-x\fP
Print major/minor device number of the blockdevice on stdout.
.SH EXIT STATUS
Zero if the directory is a mountpoint, non-zero if not.
.SH NOTES
Symbolic links are not followed, except when the \fB-x\fP option is
used. To force following symlinks, add a trailing slash to the
path of the directory.
.PP
The name of the command is misleading when the -x option is used,
but the option is useful for comparing if a directory and a device
match up, and there is no other command that can print the info easily.
.PP
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl
.SH "SEE ALSO"
.BR stat (1)

78
man/pidof.8 Normal file
View File

@ -0,0 +1,78 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH PIDOF 8 "01 Sep 1998" "" "Linux System Administrator's Manual"
.SH NAME
pidof -- find the process ID of a running program.
.SH SYNOPSIS
.B pidof
.RB [ \-s ]
.RB [ \-c ]
.RB [ \-x ]
.RB [ \-o
.IR omitpid ]
.RB [ \-o
.IR omitpid.. ]
.B program
.RB [ program.. ]
.SH DESCRIPTION
.B Pidof
finds the process id's (pids) of the named programs. It prints those
id's on the standard output. This program is on some systems used in
run-level change scripts, especially when the system has a
\fISystem-V\fP like \fIrc\fP structure. In that case these scripts are
located in /etc/rc?.d, where ? is the runlevel. If the system has
a
.B start-stop-daemon
(8) program that should be used instead.
.SH OPTIONS
.IP -s
Single shot - this instructs the program to only return one \fIpid\fP.
.IP -c
Only return process ids that are running with the same root directory.
This option is ignored for non-root users, as they will be unable to check
the current root directory of processes they do not own.
.IP -x
Scripts too - this causes the program to also return process id's of
shells running the named scripts.
.IP "-o \fIomitpid\fP"
Tells \fIpidof\fP to omit processes with that process id. The special
pid \fB%PPID\fP can be used to name the parent process of the \fIpidof\fP
program, in other words the calling shell or shell script.
.SH "EXIT STATUS"
.TP
.B 0
At least one program was found with the requested name.
.TP
.B 1
No program was found with the requested name.
.SH NOTES
\fIpidof\fP is actually the same program as \fIkillall5\fP;
the program behaves according to the name under which it is called.
.PP
When \fIpidof\fP is invoked with a full pathname to the program it
should find the pid of, it is reasonably safe. Otherwise it is possible
that it returns pids of running programs that happen to have the same name
as the program you're after but are actually other programs.
.SH SEE ALSO
.BR shutdown (8),
.BR init (8),
.BR halt (8),
.BR reboot (8),
.BR killall5 (8)
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl

1
man/poweroff.8 Normal file
View File

@ -0,0 +1 @@
.so man8/halt.8

1
man/reboot.8 Normal file
View File

@ -0,0 +1 @@
.so man8/halt.8

56
man/runlevel.8 Normal file
View File

@ -0,0 +1,56 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1997 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH RUNLEVEL 8 "May 27, 1997" "" "Linux System Administrator's Manual"
.SH NAME
runlevel -- find the previous and current system runlevel.
.SH SYNOPSIS
.B runlevel
.RI [ utmp ]
.SH DESCRIPTION
.B Runlevel
reads the system
.I utmp
file (typically
.IR /var/run/utmp )
to locate the runlevel record, and then
prints the previous and current system runlevel on its standard output,
separated by a single space. If there is no previous system
runlevel, the letter \fBN\fP will be printed instead.
.PP
If no
.I utmp
file exists, or if no runlevel record can be found,
.B runlevel
prints the word \fBunknown\fP and exits with an error.
.PP
.B Runlevel
can be used in \fIrc\fP scripts as a substitute for the System-V
\fBwho -r\fP command.
However, in newer versions of \fBinit\fP(8) this information
is also available in the environment variables \fBRUNLEVEL\fP and
\fBPREVLEVEL\fP.
.SH OPTIONS
.\"{{{ utmp
.IP \fIutmp\fP
The name of the \fIutmp\fP file to read.
.\"}}}
.SH SEE ALSO
.BR init (8),
.BR utmp (5)
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl

214
man/shutdown.8 Normal file
View File

@ -0,0 +1,214 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.\"{{{}}}
.\"{{{ Title
.TH SHUTDOWN 8 "November 12, 2003" "" "Linux System Administrator's Manual"
.\"}}}
.\"{{{ Name
.SH NAME
shutdown \- bring the system down
.\"}}}
.\"{{{ Synopsis
.SH SYNOPSIS
.B /sbin/shutdown
.RB [ \-t
.IR sec ]
.RB [ \-arkhncfFHP ]
.I time
.RI [ warning-message ]
.\"}}}
.\"{{{ Description
.SH DESCRIPTION
\fBshutdown\fP brings the system down in a secure way. All logged-in users are
notified that the system is going down, and \fBlogin\fP(1) is blocked.
It is possible to shut the system down immediately or after a specified delay.
All processes are first notified that the system is going down by the
signal \s-2SIGTERM\s0. This gives programs like \fBvi\fP(1)
the time to save the file being edited,
mail and news processing programs a chance to exit cleanly, etc.
\fBshutdown\fP does its job by signalling the \fBinit\fP process,
asking it to change the runlevel.
Runlevel \fB0\fP is used to halt the system, runlevel \fB6\fP is used
to reboot the system, and runlevel \fB1\fP is used to put to system into
a state where administrative tasks can be performed; this is the default
if neither the \fI-h\fP or \fI-r\fP flag is given to \fBshutdown\fP.
To see which actions are taken on halt or reboot see the appropriate
entries for these runlevels in the file \fI/etc/inittab\fP.
.\"}}}
.\"{{{ Options
.SH OPTIONS
.\"{{{ -a
.IP "\fB\-a\fP
Use \fB/etc/shutdown.allow\fP.
.\"}}}
.\"{{{ -t sec
.IP "\fB\-t\fP \fIsec\fP"
Tell \fBinit\fP(8) to wait \fIsec\fP seconds between sending processes the
warning and the kill signal, before changing to another runlevel.
.\"}}}
.\"{{{ -k
.IP \fB\-k\fP
Don't really shutdown; only send the warning messages to everybody.
.\"}}}
.\"{{{ -r
.IP \fB\-r\fP
Reboot after shutdown.
.\"}}}
.\"{{{ -h
.IP \fB\-h\fP
Halt or power off after shutdown.
.\"}}}
.\"{{{ -H
.IP \fB\-H\fP
Modifier to the -h flag. Halt action is to halt or drop into boot
monitor on systems that support it. Must be used with the -h flag.
.\"}}}
.\"{{{ -P
.IP \fB\-P\fP
Halt action is to turn off the power.
.\"}}}
.\"{{{ -n
.IP \fB\-n\fP
[DEPRECATED] Don't call \fBinit\fP(8) to do the shutdown but do it ourself.
The use of this option is discouraged, and its results are not always what
you'd expect.
.\"}}}
.\"{{{ -f
.IP \fB\-f\fP
Skip fsck on reboot.
.\"}}}
.\"{{{ -F
.IP \fB\-F\fP
Force fsck on reboot.
.\"}}}
.\"{{{ -c
.IP \fB\-c\fP
Cancel an already running shutdown. With this option it is of course
not possible to give the \fBtime\fP argument, but you can enter a
explanatory message on the command line that will be sent to all users.
.\"}}}
.\"{{{ time
.IP \fItime\fP
When to shutdown.
.\"}}}
.\"{{{ warning-message
.IP \fIwarning-message\fP
Message to send to all users.
.\"}}}
.PP
The \fItime\fP argument can have different formats. First, it can be an
absolute time in the format \fIhh:mm\fP, in which \fIhh\fP is the hour
(1 or 2 digits) and \fImm\fP is the minute of the hour (in two digits).
Second, it can be in the format \fB+\fP\fIm\fP, in which \fIm\fP is the
number of minutes to wait. The word \fBnow\fP is an alias for \fB+0\fP.
.PP
If shutdown is called with a delay, it will create the advisory file
.I /etc/nologin
which causes programs such as \fIlogin(1)\fP to not allow new user
logins. This file is created five minutes before the shutdown sequence
starts. Shutdown removes this file if it is stopped before it
can signal init (i.e. it is cancelled or something goes wrong).
It also removes it before calling init to change the runlevel.
.PP
The \fB\-f\fP flag means `reboot fast'. This only creates an advisory
file \fI/fastboot\fP which can be tested by the system when it comes
up again. The boot rc file can test if this file is present, and decide not
to run \fBfsck\fP(1) since the system has been shut down in the proper way.
After that, the boot process should remove \fI/fastboot\fP.
.PP
The \fB\-F\fP flag means `force fsck'. This only creates an advisory
file \fI/forcefsck\fP which can be tested by the system when it comes
up again. The boot rc file can test if this file is present, and decide
to run \fBfsck\fP(1) with a special `force' flag so that even properly
unmounted file systems get checked.
After that, the boot process should remove \fI/forcefsck\fP.
.PP
The \fB-n\fP flag causes \fBshutdown\fP not to call \fBinit\fP,
but to kill all running processes itself.
\fBshutdown\fP will then turn off quota, accounting, and swapping
and unmount all file systems.
.\"}}}
.\"{{{ Files
.SH ACCESS CONTROL
\fBshutdown\fP can be called from \fBinit\fP(8) when the magic keys
\fBCTRL-ALT-DEL\fP are pressed, by creating an appropriate entry in
\fI/etc/inittab\fP. This means that everyone who has physical access
to the console keyboard can shut the system down. To prevent this,
\fBshutdown\fP can check to see if an authorized user is logged in on
one of the virtual consoles. If \fBshutdown\fP is called with the \fB-a\fP
argument (add this to the invocation of shutdown in /etc/inittab),
it checks to see if the file \fI/etc/shutdown.allow\fP is present.
It then compares the login names in that file with the list of people
that are logged in on a virtual console (from \fI/var/run/utmp\fP). Only
if one of those authorized users \fBor root\fP is logged in, it will
proceed. Otherwise it will write the message
.sp 1
.nf
\fBshutdown: no authorized users logged in\fP
.fi
.sp 1
to the (physical) system console. The format of \fI/etc/shutdown.allow\fP
is one user name per line. Empty lines and comment lines (prefixed by a
\fB#\fP) are allowed. Currently there is a limit of 32 users in this file.
.sp 1
Note that if \fI/etc/shutdown.allow\fP is not present, the \fB-a\fP
argument is ignored.
.SH HALT OR POWEROFF
The \fB-H\fP option just sets the \fIinit\fP environment variable
\fIINIT_HALT\fP to \fIHALT\fP, and the \fB-P\fP option just sets
that variable to \fIPOWEROFF\fP. The shutdown script that calls
\fBhalt\fP(8) as the last thing in the shutdown sequence should
check these environment variables and call \fBhalt\fP(8) with
the right options for these options to actually have any effect.
Debian 3.1 (sarge) supports this.
.SH FILES
.nf
/fastboot
/etc/inittab
/etc/init.d/halt
/etc/init.d/reboot
/etc/shutdown.allow
.fi
.\"}}}
.SH NOTES
A lot of users forget to give the \fItime\fP argument
and are then puzzled by the error message \fBshutdown\fP produces. The
\fItime\fP argument is mandatory; in 90 percent of all cases this argument
will be the word \fBnow\fP.
.PP
Init can only capture CTRL-ALT-DEL and start shutdown in console mode.
If the system is running the X window System, the X server processes
all key strokes. Some X11 environments make it possible to capture
CTRL-ALT-DEL, but what exactly is done with that event depends on
that environment.
.PP
Shutdown wasn't designed to be run setuid. /etc/shutdown.allow is
not used to find out who is executing shutdown, it ONLY checks who
is currently logged in on (one of the) console(s).
.\"{{{ Author
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl
.\"}}}
.\"{{{ See also
.SH "SEE ALSO"
.BR fsck (8),
.BR init (8),
.BR halt (8),
.BR poweroff (8),
.BR reboot (8)
.\"}}}

87
man/sulogin.8 Normal file
View File

@ -0,0 +1,87 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2006 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH SULOGIN 8 "17 Jan 2006" "" "Linux System Administrator's Manual"
.SH NAME
sulogin \- Single-user login
.SH SYNOPSIS
.B sulogin
[ \fB\-e\fP ]
[ \fB\-p\fP ]
[ \fB\-t\fP \fISECONDS\fP ]
[ \fITTY\fP ]
.SH DESCRIPTION
.I sulogin
is invoked by \fBinit(8)\fP when the system goes into single user mode.
(This is done through an entry in \fIinittab(5)\fP.)
\fBInit\fP also
tries to execute \fIsulogin\fP when
the boot loader (e.g., \fBgrub\fP(8))
passes it the \fB\-b\fP option.
.PP
The user is prompted
.IP "" .5i
Give root password for system maintenance
.br
(or type Control\-D for normal startup):
.PP
\fIsulogin\fP will be connected to the current terminal, or to the
optional device that can be specified on the command line
(typically \fB/dev/console\fP).
.PP
If the \fB\-t\fP option is used then the program only waits
the given number of seconds for user input.
.PP
If the \fB\-p\fP option is used then the single-user shell is invoked
with a \fIdash\fP as the first character in \fIargv[0]\fP.
This causes the shell process to behave as a login shell.
The default is \fInot\fP to do this,
so that the shell will \fInot\fP read \fB/etc/profile\fP
or \fB$HOME/.profile\fP at startup.
.PP
After the user exits the single-user shell,
or presses control\-D at the prompt,
the system will (continue to) boot to the default runlevel.
.SH ENVIRONMENT VARIABLES
\fIsulogin\fP looks for the environment variable \fBSUSHELL\fP or
\fBsushell\fP to determine what shell to start. If the environment variable
is not set, it will try to execute root's shell from /etc/passwd. If that
fails it will fall back to \fB/bin/sh\fP.
.PP
This is very valuable together with the \fB\-b\fP option to init. To boot
the system into single user mode, with the root file system mounted read/write,
using a special "fail safe" shell that is statically linked (this example
is valid for the LILO bootprompt)
.PP
boot: linux \-b rw sushell=/sbin/sash
.SH FALLBACK METHODS
\fIsulogin\fP checks the root password using the standard method (getpwnam)
first.
Then, if the \fB\-e\fP option was specified,
\fIsulogin\fP examines these files directly to find the root password:
.PP
/etc/passwd,
.br
/etc/shadow (if present)
.PP
If they are damaged or nonexistent, sulogin will start a root shell
without asking for a password. Only use the \fB\-e\fP option if you
are sure the console is physically protected against unauthorized access.
.SH AUTHOR
Miquel van Smoorenburg <miquels@cistron.nl>
.SH SEE ALSO
init(8), inittab(5).

1
man/telinit.8 Normal file
View File

@ -0,0 +1 @@
.so man8/init.8

75
man/wall.1 Normal file
View File

@ -0,0 +1,75 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1998-2003 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH WALL 1 "15 April 2003" "" "Linux User's Manual"
.SH NAME
wall -- send a message to everybody's terminal.
.SH SYNOPSIS
.B wall
.RB [ \-n ]
.RB [ " message " ]
.SH DESCRIPTION
.B Wall
sends a message to everybody logged in with their
.IR mesg (1)
permission
set to
.BR yes .
The message can be given as an argument to
.IR wall ,
or it can be sent to
.IR wall 's
standard input. When using the standard input from a terminal,
the message should be terminated with the
.B EOF
key (usually Control-D).
.PP
The length of the message is limited to 20 lines.
For every invocation of
.I wall
a notification will be written to syslog, with facility
.B LOG_USER
and level
.BR LOG_INFO .
.SH OPTIONS
.IP \fB\-n\fn
Suppresses the normal banner printed by
.IR wall ,
changing it to "Remote broadcast message".
This option is only available for root if
.I wall
is installed set-group-id, and is used by
.IR rpc.walld (8).
.PP
.SH ENVIRONMENT
.I Wall
ignores the
.B TZ
variable - the time printed in the banner is based on the system's
local time.
.SH SEE ALSO
.IR mesg (1),
.IR rpc.rwalld (8).
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl

58
obsolete/README.RIGHT.NOW Normal file
View File

@ -0,0 +1,58 @@
WARNING:
This version of sysvinit is really different from the 2.50 and
earlier version.
Shutdown now puts the system into runlevel 6 (reboot), 0 (halt)
or 1 (single user). This can cause unexpected results if you
install the binaries from this release into Slackware distributions
older than Slackware 3.0.
SUPPORTED DISTRIBUTIONS:
The binaries from this package can be installed in:
o Debian 1.3 and later
o RedHat 3.x and later
o Slackware 3.0 (UNTESTED but it might work - no complaints yet).
Also read the INIT.README in the slackware/ directory.
o Slackware 2.x: see the slackware/ directory
Do not install any of the scripts from the debian/ directory unless
you know what you are doing.
UNSUPPORTED DISTRIBUTIONS:
o The rest :)
If you have a non-supported system, please upgrade to the latest version
of your distribution that supports the Linux 2.0.x kernel (probably
the reason why you are installing this newer sysvinit).
You might get away by installing *just* the "init" binary, and nothing
else. Do _not_ replace your existing halt, reboot or shutdown programs.
HOW TO NON DESTRUCTIVELY TEST THE NEW INIT:
Install *just* the init binary as /sbin/init.new. Now reboot the system,
and stop your bootloader so you can give arguments on the command line.
With LILO you can usually achieve this by keeping the SHIFT key
pressed during boot up. Enter the name of the kernel image (for LILO,
TAB shows a list) followed by the argument "init=/sbin/init.new".
The name "init.new" is special, do not use something like "init.test".
For example:
boot: linux init=/sbin/init.new
YOU CANNOT SHUTDOWN IN A CLEAN WAY AFTER THIS. Your best bet is to use
the "-n" flag to shutdown. This is because init is not running as process #1
if you use this method. Anyway, if this works, you can remove the old init
and copy the new init into place.
DISCLAIMER:
If it breaks you get to keep both pieces. If you want to run the latest
Linux 2.0.x kernel and you can't get init to work just upgrade your entire
distribution to a newer version that supports the 2.0.x kernel properly.

67
obsolete/bootlogd.init Executable file
View File

@ -0,0 +1,67 @@
#! /bin/sh
#
# bootlogd One of the first scripts to be executed. Starts or stops
# the bootlogd log program. If this script is called as
# "stop-bootlogd", it will stop the daemon instead of
# starting it even when called with the "start" argument.
#
# Version: @(#)bootlogd 2.77 24-Aug-1999 miquels@cistron.nl
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/sbin/bootlogd
NAME=bootlogd
DESC="Bootlog daemon"
PIDFILE=/var/run/$NAME.pid
test -f $DAEMON || exit 0
## set -e # not needed
. /etc/default/rcS
case "$0" in
*stop-bootlog*)
stopper=yes
;;
esac
case "$1" in
start|stop)
if [ "$stopper" ] || [ "$1" = "stop" ]
then
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --exec $DAEMON
else
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --exec $DAEMON -- -r
fi
if [ "$stopper" ] && [ -f /var/log/boot.log ] && \
[ -f /var/log/boot.log~ ]
then
cd /var/log
savelog -p -c 5 boot.log > /dev/null 2>&1
mv boot.log.0 boot.log
mv boot.log~ boot.log.0
fi
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
$PIDFILE --exec $DAEMON -- -p $PIDFILE
sleep 1
start-stop-daemon --start --quiet --pidfile \
$PIDFILE --exec $DAEMON -- -p $PIDFILE
echo "$NAME."
;;
*)
N=${0##*/}
N=${N#[SK]??}
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

73
obsolete/powerd.8 Normal file
View File

@ -0,0 +1,73 @@
'\" -*- coding: UTF-8 -*-
.\" Copyright (C) 1994 Miquel van Smoorenburg.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.\"
.TH POWERD 8 "Feb 14, 1994" "" "Linux System Administrator's Manual"
.SH NAME
.\" powerd \(em monitor a serial line connected to an UPS.
powerd -- monitor a serial line connected to an UPS.
.SH SYNOPSIS
.B /sbin/powerd
.RB " serial-device "
.SH DESCRIPTION
.B Powerd
is a daemon process that sits in the background and monitors the state
of the DCD line of the serial device. This line is meant to be
connected to a UPS (Uninterruptible Power Supply) so that \fBpowerd\fP knows
about the state of the UPS. As soon as \fBpowerd\fP senses that the
power is failing (it sees that DCD goes low) it notifies \fBinit\fP(8),
and \fBinit\fP then executes the \fBpowerwait\fP and \fBpowerfail\fP entries.
If \fBpowerd\fP senses that the power has been restored, it notifies \fBinit\fP
again and \fBinit\fP will execute the \fBpowerokwait\fP entries.
.SH ARGUMENTS
.IP serial-device
Some serial port that is not being used by some other device, and does not
share an interrupt with any other serial port.
.SH DIAGNOSTICS
\fBPowerd\fP regularly checks the \fBDSR\fP line to see if it's high.
\fBDSR\fP should be directly connected to \fBDTR\fP and \fBpowerd\fP
keeps that line high, so if \fBDSR\fP is low then something is wrong
with the connection. \fBPowerd\fP will notify you about this fact every
two minutes. When it sees that the connection has been restored it
will say so.
.SH HOWTO
It's pretty simple to connect your UPS to the Linux machine. The steps
are easy:
.TP 0.5i
.B 1.
Make sure you have an UPS with a simple relay output: it should
close its connections (make) if the power is gone, and it should
open its connections (break) if the power is good.
.TP 0.5i
.B 2.
Buy a serial plug. Connect the DTR line to the DSR line directly.
Connect the DTR line and the DCD line with a \fB10 kilo ohm\fP
resistor. Now connect the relay output of the UPS to GROUND
and the DCD line. If you don't know what pins DSR, DTR, DCD and
GROUND are you can always ask at the store where you bought the plug.
.TP 0.5i
.B 3.
You're all set.
.SH BUGS
Well, not a real bug but \fBpowerd\fP should be able to do a broadcast or
something on the ethernet in case more Linux-boxes are connected to
the same UPS and only one of them is connected to the UPS status line.
.SH SEE ALSO
.BR shutdown (8),
.BR init (8),
.BR inittab (5)
.SH AUTHOR
Miquel van Smoorenburg, miquels@cistron.nl

36
obsolete/powerd.README Normal file
View File

@ -0,0 +1,36 @@
There are 2 *much* better powerd's than the one that is included as
an example with sysvinit. The powerd.c in this distribution is just ment
as a programming example, not to be used in a real life situation.
1. GENPOWERD.
This is a powerd written by Tom Webster <webster@kaiwan.com>. It's a
nice package, you can find info at http://www.kaiwan.com/~webster/genpower.html
2. POWERD-2.0.
This is another powerd, written by rubini@ipvvis.unipv.it (Alessandro Rubini).
The main advantage over genpowerd is that it can signal other machines over
the network.
This LSM may be out of date. Please check if a newer version exists.
Begin3
Title: powerd
Version: 2.0
Entered-date: Sep 26 1995
Description: A daemon to shut down and up computers connected to ups's.
Network-aware: server-mode and client-mode allowed.
Keywords: ups, powerd, init
Author: Alessandro Rubini (based on Miquel van Smoorenburg's work).
Maintained-by: rubini@ipvvis.unipv.it (Alessandro Rubini)
Primary-site: sunsite.unc.edu /pub/Linux/system/UPS/powerd-2.0.tar.gz
25kB powerd-2.0.tar.gz
1kB powerd-2.0.lsm
Alternate-site:
Original-site: iride.unipv.it /pub/linux
25kB powerd-2.0.tar.gz
1kB powerd-2.0.lsm
Platform: Linux. Porting is foreseeable.
Copying-policy: GPL
End

201
obsolete/powerd.c Normal file
View File

@ -0,0 +1,201 @@
/*
* powerd Monitor the DCD line of a serial port connected to
* an UPS. If the power goes down, notify init.
* If the power comes up again, notify init again.
* As long as the power is OK, the DCD line should be
* "HIGH". When the power fails, DCD should go "LOW".
* Powerd keeps DTR high so that you can connect
* DCD and DTR with a resistor of 10 Kilo Ohm and let the
* UPS or some relais pull the DCD line to ground.
* You also need to connect DTR and DSR together. This
* way, powerd can check now and then if DSR is high
* so it knows the UPS is connected!!
*
* Usage: powerd /dev/cua4 (or any other serial device).
*
* Author: Miquel van Smoorenburg, <miquels@drinkel.cistron.nl>.
*
* Version: 1.31, 29-Feb-1996.
*
* This program was originally written for my employer,
* ** Cistron Electronics **
* who has given kind permission to release this program
* for general puppose.
*
* Copyright (C) 1991-1996 Cistron Electronics.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Use the new way of communicating with init. */
#define NEWINIT
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include "paths.h"
#ifdef NEWINIT
#include "initreq.h"
#endif
#ifndef SIGPWR
# define SIGPWR SIGUSR1
#endif
#ifdef NEWINIT
void alrm_handler()
{
}
#endif
/* Tell init the power has either gone or is back. */
void powerfail(ok)
int ok;
{
int fd;
#ifdef NEWINIT
struct init_request req;
/* Fill out the request struct. */
memset(&req, 0, sizeof(req));
req.magic = INIT_MAGIC;
req.cmd = ok ? INIT_CMD_POWEROK : INIT_CMD_POWERFAIL;
/* Open the fifo (with timeout) */
signal(SIGALRM, alrm_handler);
alarm(3);
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0
&& write(fd, &req, sizeof(req)) == sizeof(req)) {
close(fd);
return;
}
/* Fall through to the old method.. */
#endif
/* Create an info file for init. */
unlink(PWRSTAT);
if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) {
if (ok)
write(fd, "OK\n", 3);
else
write(fd, "FAIL\n", 5);
close(fd);
}
kill(1, SIGPWR);
}
/* Main program. */
int main(int argc, char **argv)
{
int fd;
int dtr_bit = TIOCM_DTR;
int flags;
int status, oldstat = -1;
int count = 0;
int tries = 0;
if (argc < 2) {
fprintf(stderr, "Usage: powerd <device>\n");
exit(1);
}
/* Start syslog. */
openlog("powerd", LOG_CONS|LOG_PERROR, LOG_DAEMON);
/* Open monitor device. */
if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
syslog(LOG_ERR, "%s: %s", argv[1], sys_errlist[errno]);
closelog();
exit(1);
}
/* Line is opened, so DTR is high. Force it anyway to be sure. */
ioctl(fd, TIOCMBIS, &dtr_bit);
/* Daemonize. */
switch(fork()) {
case 0: /* Child */
closelog();
setsid();
break;
case -1: /* Error */
syslog(LOG_ERR, "can't fork.");
closelog();
exit(1);
default: /* Parent */
closelog();
exit(0);
}
/* Restart syslog. */
openlog("powerd", LOG_CONS, LOG_DAEMON);
/* Now sample the DCD line. */
while(1) {
/* Get the status. */
ioctl(fd, TIOCMGET, &flags);
/* Check the connection: DSR should be high. */
tries = 0;
while((flags & TIOCM_DSR) == 0) {
/* Keep on trying, and warn every two minutes. */
if ((tries % 60) == 0)
syslog(LOG_ALERT, "UPS connection error");
sleep(2);
tries++;
ioctl(fd, TIOCMGET, &flags);
}
if (tries > 0)
syslog(LOG_ALERT, "UPS connection OK");
/* Calculate present status. */
status = (flags & TIOCM_CAR);
/* Did DCD drop to zero? Then the power has failed. */
if (oldstat != 0 && status == 0) {
count++;
if (count > 3)
powerfail(0);
else {
sleep(1);
continue;
}
}
/* Did DCD come up again? Then the power is back. */
if (oldstat == 0 && status > 0) {
count++;
if (count > 3)
powerfail(1);
else {
sleep(1);
continue;
}
}
/* Reset count, remember status and sleep 2 seconds. */
count = 0;
oldstat = status;
sleep(2);
}
/* Never happens */
return(0);
}

58
obsolete/powerd.cfg Normal file
View File

@ -0,0 +1,58 @@
# Example configuration for power daemon.
# NOTE: this is not implemented yet, just a design.
#
# @(#) powerd.cfg 1.01 01-Oct-1994 MvS
#
# This is the setup section. It sets up the default line
# signals that your UPS likes to see.
[ setup ]
dtr = 1
rts = 1
baud = 2400
send "AAAA"
# Now: how to tell UPS to turn off the power.
[ powerdown ]
dtr = 0
send "BYE"
# How to monitor the UPS, or a remote UPS.
# Possible line signals: dcd cts dsr ring
#
# Comment out the parts you don't want.
#
# All of this (1, 2, 3) can be combined.
[ monitor ]
# First, do we want to broadcast the UPS status
# on ethernet when something happens?
# Comment out to disable.
# Syntax: address, portnumber
# address: broadcast adress on ethernet
# portnumber: unused priviliged port (under 1024)
broadcast = 10.0.33.255,15
# monitor type 1. This tells powerd to monitor line signals.
ok = dcd
fail = !dcd
lowbat = rts
# Monitor type 2. Tell powerd to look for data.
ok = "OK"
fail = "!"
# Monitor type 3. Listen to the ethernet.
#
# Warn_host is the hostname of the system with the UPS
# This is for security, so that someone on a DOS box
# can't spoof the powerd broadcast. The number after it
# is the portnumber to listen to (see above: broadcast).
#
# Note: if the broadcast address set above is enabled
# and we receive a message from a remote powerd, we check
# the received broadcast address. If this is the same
# as from the broadcast we just received,
# it will not be repeated (guess why).
remote = warn_host,15

70
obsolete/utmpdump.c.OLD Normal file
View File

@ -0,0 +1,70 @@
/*
* utmpdump Simple program to dump UTMP and WTMP files in
* raw format, so they can be examined.
*
* Version: @(#)utmpdump.c 13-Aug-1996 1.00 miquels@cistron.nl
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-1996 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <utmp.h>
#include <time.h>
void dump(fp)
FILE *fp;
{
struct utmp ut;
int f;
time_t tm;
while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) {
for(f = 0; f < 12; f++) if (ut.ut_line[f] == ' ') ut.ut_line[f] = '_';
for(f = 0; f < 8; f++) if (ut.ut_name[f] == ' ') ut.ut_name[f] = '_';
tm = ut.ut_time;
printf("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s]\n",
ut.ut_type, ut.ut_pid, ut.ut_id, ut.ut_user,
ut.ut_line, 4 + ctime(&tm));
}
}
int main(argc, argv)
int argc;
char **argv;
{
int f;
FILE *fp;
if (argc < 2) {
argc = 2;
argv[1] = UTMP_FILE;
}
for(f = 1; f < argc; f++) {
if (strcmp(argv[f], "-") == 0) {
printf("Utmp dump of stdin\n");
dump(stdin);
} else if ((fp = fopen(argv[f], "r")) != NULL) {
printf("Utmp dump of %s\n", argv[f]);
dump(fp);
fclose(fp);
} else
perror(argv[f]);
}
return(0);
}

168
src/Makefile Normal file
View File

@ -0,0 +1,168 @@
#
# Makefile Makefile for the systemV init suite.
# Targets: all compiles everything
# install installs the binaries (not the scripts)
# clean cleans up object files
# clobber really cleans up
#
# Version: @(#)Makefile 2.85-13 23-Mar-2004 miquels@cistron.nl
#
CC = gcc
CFLAGS = -ansi -W -Wall -O2 -fomit-frame-pointer -D_GNU_SOURCE
LDFLAGS = -s
STATIC =
# For some known distributions we do not build all programs, otherwise we do.
BIN =
SBIN = init halt shutdown runlevel killall5
USRBIN = last mesg
MAN1 = last.1 lastb.1 mesg.1
MAN5 = initscript.5 inittab.5
MAN8 = halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8
MAN8 += shutdown.8 telinit.8
ifeq ($(DISTRO),)
BIN += mountpoint
SBIN += sulogin bootlogd
USRBIN += utmpdump wall
MAN1 += mountpoint.1 wall.1
MAN8 += sulogin.8 bootlogd.8
endif
ifeq ($(DISTRO),Debian)
BIN += mountpoint
SBIN += sulogin bootlogd
MAN1 += mountpoint.1
MAN8 += sulogin.8 bootlogd.8
endif
ifeq ($(DISTRO),Owl)
USRBIN += wall
MAN1 += wall.1
endif
BIN_OWNER = root
BIN_GROUP = root
BIN_COMBO = $(BIN_OWNER):$(BIN_GROUP)
STRIP = strip -s -R .comment
INSTALL_EXEC = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 755
INSTALL_DATA = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 644
MANDIR = /usr/share/man
ifeq ($(WITH_SELINUX),yes)
SELINUX_DEF=-DWITH_SELINUX
INIT_SELIBS=-lsepol -lselinux
SULOGIN_SELIBS=-lselinux
else
SELINUX_DEF=
INIT_SELIBS=
SULOGIN_SELIBS=
endif
# Additional libs for GNU libc.
ifneq ($(wildcard /usr/lib/libcrypt.a),)
LCRYPT = -lcrypt
endif
all: $(BIN) $(SBIN) $(USRBIN)
init: init.o init_utmp.o
$(CC) $(LDFLAGS) $(STATIC) -o $@ init.o init_utmp.o $(INIT_SELIBS)
halt: halt.o ifdown.o hddown.o utmp.o reboot.h
$(CC) $(LDFLAGS) -o $@ halt.o ifdown.o hddown.o utmp.o
last: last.o oldutmp.h
$(CC) $(LDFLAGS) -o $@ last.o
mesg: mesg.o
$(CC) $(LDFLAGS) -o $@ mesg.o
mountpoint: mountpoint.o
$(CC) $(LDFLAGS) -o $@ mountpoint.o
utmpdump: utmpdump.o
$(CC) $(LDFLAGS) -o $@ utmpdump.o
runlevel: runlevel.o
$(CC) $(LDFLAGS) -o $@ runlevel.o
sulogin: sulogin.o
$(CC) $(LDFLAGS) $(STATIC) $(SELINUX_DEF) -o $@ $^ $(LCRYPT) $(SULOGIN_SELIBS)
wall: dowall.o wall.o
$(CC) $(LDFLAGS) -o $@ dowall.o wall.o
shutdown: dowall.o shutdown.o utmp.o reboot.h
$(CC) $(LDFLAGS) -o $@ dowall.o shutdown.o utmp.o
bootlogd: bootlogd.o
$(CC) $(LDFLAGS) -o $@ bootlogd.o -lutil
sulogin.o: sulogin.c
$(CC) -c $(CFLAGS) $(SELINUX_DEF) sulogin.c
init.o: init.c init.h set.h reboot.h initreq.h
$(CC) -c $(CFLAGS) $(SELINUX_DEF) init.c
utmp.o: utmp.c init.h
$(CC) -c $(CFLAGS) utmp.c
init_utmp.o: utmp.c init.h
$(CC) -c $(CFLAGS) -DINIT_MAIN utmp.c -o init_utmp.o
cleanobjs:
rm -f *.o *.bak
clean: cleanobjs
@echo Type \"make clobber\" to really clean up.
clobber: cleanobjs
rm -f $(BIN) $(SBIN) $(USRBIN)
distclean: clobber
install:
for i in $(BIN); do \
$(STRIP) $$i ; \
$(INSTALL_EXEC) $$i $(ROOT)/bin/ ; \
done
for i in $(SBIN); do \
$(STRIP) $$i ; \
$(INSTALL_EXEC) $$i $(ROOT)/sbin/ ; \
done
for i in $(USRBIN); do \
$(STRIP) $$i ; \
$(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
done
# $(INSTALL_EXEC) etc/initscript.sample $(ROOT)/etc/
ln -sf halt $(ROOT)/sbin/reboot
ln -sf halt $(ROOT)/sbin/poweroff
ln -sf init $(ROOT)/sbin/telinit
ln -sf /sbin/killall5 $(ROOT)/bin/pidof
if [ ! -f $(ROOT)/usr/bin/lastb ]; then \
ln -sf last $(ROOT)/usr/bin/lastb; \
fi
$(INSTALL_DATA) initreq.h $(ROOT)/usr/include/
for i in $(MAN1); do \
$(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man1/; \
done
for i in $(MAN5); do \
$(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man5/; \
done
for i in $(MAN8); do \
$(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man8/; \
done
ifeq ($(ROOT),)
#
# This part is skipped on Debian systems, the
# debian.preinst script takes care of it.
@if [ ! -p /dev/initctl ]; then \
echo "Creating /dev/initctl"; \
rm -f /dev/initctl; \
mknod -m 600 /dev/initctl p; fi
endif

657
src/bootlogd.c Normal file
View File

@ -0,0 +1,657 @@
/*
* bootlogd.c Store output from the console during bootup into a file.
* The file is usually located on the /var partition, and
* gets written (and fsynced) as soon as possible.
*
* Version: @(#)bootlogd 2.86pre 12-Jan-2004 miquels@cistron.nl
*
* Bugs: Uses openpty(), only available in glibc. Sorry.
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* *NOTE* *NOTE* *NOTE*
* This is a PROOF OF CONCEPT IMPLEMENTATION
*
* I have bigger plans for Debian, but for now
* this has to do ;)
*
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <dirent.h>
#include <fcntl.h>
#include <pty.h>
#include <ctype.h>
#ifdef __linux__
#include <sys/mount.h>
#endif
char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels@cistron.nl";
#define LOGFILE "/var/log/boot"
char ringbuf[32768];
char *endptr = ringbuf + sizeof(ringbuf);
char *inptr = ringbuf;
char *outptr = ringbuf;
int got_signal = 0;
int didnl = 1;
int createlogfile = 0;
int syncalot = 0;
struct line {
char buf[256];
int pos;
} line;
/*
* Console devices as listed on the kernel command line and
* the mapping to actual devices in /dev
*/
struct consdev {
char *cmdline;
char *dev1;
char *dev2;
} consdev[] = {
{ "ttyB", "/dev/ttyB%s", NULL },
{ "ttySC", "/dev/ttySC%s", "/dev/ttsc/%s" },
{ "ttyS", "/dev/ttyS%s", "/dev/tts/%s" },
{ "tty", "/dev/tty%s", "/dev/vc/%s" },
{ "hvc", "/dev/hvc%s", "/dev/hvc/%s" },
{ NULL, NULL, NULL },
};
/*
* Devices to try as console if not found on kernel command line.
* Tried from left to right (as opposed to kernel cmdline).
*/
char *defcons[] = { "tty0", "hvc0", "ttyS0", "ttySC0", "ttyB0", NULL };
/*
* Catch signals.
*/
void handler(int sig)
{
got_signal = sig;
}
/*
* Scan /dev and find the device name.
* Side-effect: directory is changed to /dev
*
* FIXME: scan subdirectories for devfs support ?
*/
int findtty(char *res, int rlen, dev_t dev)
{
DIR *dir;
struct dirent *ent;
struct stat st;
int r = 0;
if (chdir("/dev") < 0 || (dir = opendir(".")) == NULL) {
perror("bootlogd: /dev");
return -1;
}
while ((ent = readdir(dir)) != NULL) {
if (lstat(ent->d_name, &st) != 0)
continue;
if (!S_ISCHR(st.st_mode))
continue;
if (st.st_rdev == dev) {
break;
}
}
if (ent == NULL) {
fprintf(stderr, "bootlogd: cannot find console device "
"%d:%d in /dev\n", major(dev), minor(dev));
r = -1;
} else if (strlen(ent->d_name) + 5 >= rlen) {
fprintf(stderr, "bootlogd: console device name too long\n");
r = -1;
} else
snprintf(res, rlen, "/dev/%s", ent->d_name);
closedir(dir);
return r;
}
/*
* For some reason, openpty() in glibc sometimes doesn't
* work at boot-time. It must be a bug with old-style pty
* names, as new-style (/dev/pts) is not available at that
* point. So, we find a pty/tty pair ourself if openpty()
* fails for whatever reason.
*/
int findpty(int *master, int *slave, char *name)
{
char pty[16];
char tty[16];
int i, j;
int found;
if (openpty(master, slave, name, NULL, NULL) >= 0)
return 0;
found = 0;
for (i = 'p'; i <= 'z'; i++) {
for (j = '0'; j <= 'f'; j++) {
if (j == '9' + 1) j = 'a';
sprintf(pty, "/dev/pty%c%c", i, j);
sprintf(tty, "/dev/tty%c%c", i, j);
if ((*master = open(pty, O_RDWR|O_NOCTTY)) >= 0) {
*slave = open(tty, O_RDWR|O_NOCTTY);
if (*slave >= 0) {
found = 1;
break;
}
}
}
if (found) break;
}
if (found < 0) return -1;
if (name) strcpy(name, tty);
return 0;
}
/*
* See if a console taken from the kernel command line maps
* to a character device we know about, and if we can open it.
*/
int isconsole(char *s, char *res, int rlen)
{
struct consdev *c;
int l, sl, i, fd;
char *p, *q;
sl = strlen(s);
for (c = consdev; c->cmdline; c++) {
l = strlen(c->cmdline);
if (sl <= l) continue;
p = s + l;
if (strncmp(s, c->cmdline, l) != 0 || !isdigit(*p))
continue;
for (i = 0; i < 2; i++) {
snprintf(res, rlen, i ? c->dev1 : c->dev2, p);
if ((q = strchr(res, ',')) != NULL) *q = 0;
if ((fd = open(res, O_RDONLY|O_NONBLOCK)) >= 0) {
close(fd);
return 1;
}
}
}
return 0;
}
/*
* Find out the _real_ console. Assume that stdin is connected to
* the console device (/dev/console).
*/
int consolename(char *res, int rlen)
{
#ifdef TIOCGDEV
unsigned int kdev;
#endif
struct stat st, st2;
char buf[256];
char *p;
int didmount = 0;
int n, r;
int fd;
fstat(0, &st);
if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
/*
* Old kernel, can find real device easily.
*/
return findtty(res, rlen, st.st_rdev);
}
#ifdef TIOCGDEV
if (ioctl(0, TIOCGDEV, &kdev) == 0)
return findtty(res, rlen, (dev_t)kdev);
if (errno != ENOIOCTLCMD) return -1;
#endif
#ifdef __linux__
/*
* Read /proc/cmdline.
*/
stat("/", &st);
if (stat("/proc", &st2) < 0) {
perror("bootlogd: /proc");
return -1;
}
if (st.st_dev == st2.st_dev) {
if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
perror("bootlogd: mount /proc");
return -1;
}
didmount = 1;
}
n = 0;
r = -1;
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
perror("bootlogd: /proc/cmdline");
} else {
buf[0] = 0;
if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
r = 0;
else
perror("bootlogd: /proc/cmdline");
close(fd);
}
if (didmount) umount("/proc");
if (r < 0) return r;
/*
* OK, so find console= in /proc/cmdline.
* Parse in reverse, opening as we go.
*/
p = buf + n;
*p-- = 0;
r = -1;
while (p >= buf) {
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
*p-- = 0;
continue;
}
if (strncmp(p, "console=", 8) == 0 &&
isconsole(p + 8, res, rlen)) {
r = 0;
break;
}
p--;
}
if (r == 0) return r;
#endif
/*
* Okay, no console on the command line -
* guess the default console.
*/
for (n = 0; defcons[n]; n++)
if (isconsole(defcons[n], res, rlen))
return 0;
fprintf(stderr, "bootlogd: cannot deduce real console device\n");
return -1;
}
/*
* Write data and make sure it's on disk.
*/
void writelog(FILE *fp, unsigned char *ptr, int len)
{
time_t t;
char *s;
char tmp[8];
int olen = len;
int dosync = 0;
int tlen;
while (len > 0) {
tmp[0] = 0;
if (didnl) {
time(&t);
s = ctime(&t);
fprintf(fp, "%.24s: ", s);
didnl = 0;
}
switch (*ptr) {
case 27: /* ESC */
strcpy(tmp, "^[");
break;
case '\r':
line.pos = 0;
break;
case 8: /* ^H */
if (line.pos > 0) line.pos--;
break;
case '\n':
didnl = 1;
dosync = syncalot;
break;
case '\t':
line.pos += (line.pos / 8 + 1) * 8;
if (line.pos >= sizeof(line.buf))
line.pos = sizeof(line.buf) - 1;
break;
case 32 ... 127:
case 161 ... 255:
tmp[0] = *ptr;
tmp[1] = 0;
break;
default:
sprintf(tmp, "\\%03o", *ptr);
break;
}
ptr++;
len--;
tlen = strlen(tmp);
if (tlen && (line.pos + tlen < sizeof(line.buf))) {
memcpy(line.buf + line.pos, tmp, tlen);
line.pos += tlen;
}
if (didnl) {
fprintf(fp, "%s\n", line.buf);
memset(&line, 0, sizeof(line));
}
}
if (dosync) {
fflush(fp);
fdatasync(fileno(fp));
}
outptr += olen;
if (outptr >= endptr)
outptr = ringbuf;
}
/*
* Print usage message and exit.
*/
void usage(void)
{
fprintf(stderr, "Usage: bootlogd [-v] [-r] [-d] [-s] [-c] [-p pidfile] [-l logfile]\n");
exit(1);
}
int open_nb(char *buf)
{
int fd, n;
if ((fd = open(buf, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
return -1;
n = fcntl(fd, F_GETFL);
n &= ~(O_NONBLOCK);
fcntl(fd, F_SETFL, n);
return fd;
}
/*
* We got a write error on the real console. If its an EIO,
* somebody hung up our filedescriptor, so try to re-open it.
*/
int write_err(int pts, int realfd, char *realcons, int e)
{
int fd;
if (e != EIO) {
werr:
close(pts);
fprintf(stderr, "bootlogd: writing to console: %s\n",
strerror(e));
return -1;
}
close(realfd);
if ((fd = open_nb(realcons)) < 0)
goto werr;
return fd;
}
int main(int argc, char **argv)
{
FILE *fp;
struct timeval tv;
fd_set fds;
char buf[1024];
char realcons[1024];
char *p;
char *logfile;
char *pidfile;
int rotate;
int dontfork;
int ptm, pts;
int realfd;
int n, m, i;
int todo;
fp = NULL;
logfile = LOGFILE;
pidfile = NULL;
rotate = 0;
dontfork = 0;
while ((i = getopt(argc, argv, "cdsl:p:rv")) != EOF) switch(i) {
case 'l':
logfile = optarg;
break;
case 'r':
rotate = 1;
break;
case 'v':
printf("%s\n", Version);
exit(0);
break;
case 'p':
pidfile = optarg;
break;
case 'c':
createlogfile = 1;
break;
case 'd':
dontfork = 1;
break;
case 's':
syncalot = 1;
break;
default:
usage();
break;
}
if (optind < argc) usage();
signal(SIGTERM, handler);
signal(SIGQUIT, handler);
signal(SIGINT, handler);
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
/*
* Open console device directly.
*/
if (consolename(realcons, sizeof(realcons)) < 0)
return 1;
if (strcmp(realcons, "/dev/tty0") == 0)
strcpy(realcons, "/dev/tty1");
if (strcmp(realcons, "/dev/vc/0") == 0)
strcpy(realcons, "/dev/vc/1");
if ((realfd = open_nb(realcons)) < 0) {
fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno));
return 1;
}
/*
* Grab a pty, and redirect console messages to it.
*/
ptm = -1;
pts = -1;
buf[0] = 0;
if (findpty(&ptm, &pts, buf) < 0) {
fprintf(stderr,
"bootlogd: cannot allocate pseudo tty: %s\n",
strerror(errno));
return 1;
}
(void)ioctl(0, TIOCCONS, NULL);
#if 1
/* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
if ((n = open("/dev/tty0", O_RDWR)) >= 0) {
(void)ioctl(n, TIOCCONS, NULL);
close(n);
}
#endif
if (ioctl(pts, TIOCCONS, NULL) < 0) {
fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n",
buf, strerror(errno));
return 1;
}
/*
* Fork and write pidfile if needed.
*/
if (!dontfork) {
pid_t child_pid = fork();
switch (child_pid) {
case -1: /* I am parent and the attempt to create a child failed */
fprintf(stderr, "bootlogd: fork failed: %s\n",
strerror(errno));
exit(1);
break;
case 0: /* I am the child */
break;
default: /* I am parent and got child's pid */
exit(0);
break;
}
setsid();
}
if (pidfile) {
unlink(pidfile);
if ((fp = fopen(pidfile, "w")) != NULL) {
fprintf(fp, "%d\n", (int)getpid());
fclose(fp);
}
fp = NULL;
}
/*
* Read the console messages from the pty, and write
* to the real console and the logfile.
*/
while (!got_signal) {
/*
* We timeout after 5 seconds if we still need to
* open the logfile. There might be buffered messages
* we want to write.
*/
tv.tv_sec = 0;
tv.tv_usec = 500000;
FD_ZERO(&fds);
FD_SET(ptm, &fds);
if (select(ptm + 1, &fds, NULL, NULL, &tv) == 1) {
/*
* See how much space there is left, read.
*/
if ((n = read(ptm, inptr, endptr - inptr)) >= 0) {
/*
* Write data (in chunks if needed)
* to the real output device.
*/
m = n;
p = inptr;
while (m > 0) {
i = write(realfd, p, m);
if (i >= 0) {
m -= i;
p += i;
continue;
}
/*
* Handle EIO (somebody hung
* up our filedescriptor)
*/
realfd = write_err(pts, realfd,
realcons, errno);
if (realfd >= 0) continue;
got_signal = 1; /* Not really */
break;
}
/*
* Increment buffer position. Handle
* wraps, and also drag output pointer
* along if we cross it.
*/
inptr += n;
if (inptr - n < outptr && inptr > outptr)
outptr = inptr;
if (inptr >= endptr)
inptr = ringbuf;
if (outptr >= endptr)
outptr = ringbuf;
}
}
/*
* Perhaps we need to open the logfile.
*/
if (fp == NULL && access(logfile, F_OK) == 0) {
if (rotate) {
snprintf(buf, sizeof(buf), "%s~", logfile);
rename(logfile, buf);
}
fp = fopen(logfile, "a");
}
if (fp == NULL && createlogfile)
fp = fopen(logfile, "a");
if (inptr >= outptr)
todo = inptr - outptr;
else
todo = endptr - outptr;
if (fp && todo)
writelog(fp, outptr, todo);
}
if (fp) {
if (!didnl) fputc('\n', fp);
fclose(fp);
}
close(pts);
close(ptm);
close(realfd);
return 0;
}

236
src/dowall.c Normal file
View File

@ -0,0 +1,236 @@
/*
* dowall.c Write to all users on the system.
*
* Author: Miquel van Smoorenburg, miquels@cistron.nl
*
* Version: @(#)dowall.c 2.85-5 02-Jul-2003 miquels@cistron.nl
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2003 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <utmp.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>
static sigjmp_buf jbuf;
/*
* Alarm handler
*/
/*ARGSUSED*/
static void handler(int arg)
{
siglongjmp(jbuf, 1);
}
/*
* Print a text, escape all characters not in Latin-1.
*/
static void feputs(char *line, FILE *fp)
{
unsigned char *p;
for (p = (unsigned char *)line; *p; p++) {
if (strchr("\t\r\n", *p) ||
(*p >= 32 && *p <= 127) || (*p >= 160)) {
fputc(*p, fp);
} else {
fprintf(fp, "^%c", (*p & 0x1f) + 'A' - 1);
}
}
fflush(fp);
}
static void getuidtty(char **userp, char **ttyp)
{
struct passwd *pwd;
uid_t uid;
char *tty;
static char uidbuf[32];
static char ttynm[UT_LINESIZE + 4];
static int init = 0;
if (!init) {
uid = getuid();
if ((pwd = getpwuid(uid)) != NULL) {
uidbuf[0] = 0;
strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
} else {
sprintf(uidbuf, uid ? "uid %d" : "root", (int)uid);
}
if ((tty = ttyname(0)) != NULL) {
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
sprintf(ttynm, "(%.28s) ", tty);
} else
ttynm[0] = 0;
init++;
}
*userp = uidbuf;
*ttyp = ttynm;
}
/*
* Check whether given filename looks like tty device.
*/
static int file_isatty(const char *fname)
{
struct stat st;
int major;
if (stat(fname, &st) < 0)
return 0;
if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
return 0;
/*
* It would be an impossible task to list all major/minors
* of tty devices here, so we just exclude the obvious
* majors of which just opening has side-effects:
* printers and tapes.
*/
major = major(st.st_dev);
if (major == 1 || major == 2 || major == 6 || major == 9 ||
major == 12 || major == 16 || major == 21 || major == 27 ||
major == 37 || major == 96 || major == 97 || major == 206 ||
major == 230) return 0;
return 1;
}
/*
* Wall function.
*/
void wall(char *text, int fromshutdown, int remote)
{
FILE *tp;
struct sigaction sa;
struct utmp *utmp;
time_t t;
char term[UT_LINESIZE+6];
char line[81];
char hostname[256]; /* HOST_NAME_MAX+1 */
char *date, *p;
char *user, *tty;
int fd, flags;
/*
* Make sure tp and fd aren't in a register. Some versions
* of gcc clobber those after longjmp (or so I understand).
*/
(void) &tp;
(void) &fd;
getuidtty(&user, &tty);
/* Get and report current hostname, to make it easier to find
out which machine is being shut down. */
if (0 != gethostname(hostname, sizeof(hostname))) {
strncpy(hostname, "[unknown]", sizeof(hostname)-1);
}
/* If hostname is truncated, it is unspecified if the string
is null terminated or not. Make sure we know it is null
terminated. */
hostname[sizeof(hostname)-1] = 0;
/* Get the time */
time(&t);
date = ctime(&t);
for(p = date; *p && *p != '\n'; p++)
;
*p = 0;
if (remote) {
snprintf(line, sizeof(line),
"\007\r\nRemote broadcast message (%s):\r\n\r\n",
date);
} else {
snprintf(line, sizeof(line),
"\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n",
user, hostname, tty, date);
}
/*
* Fork to avoid us hanging in a write()
*/
if (fork() != 0)
return;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
setutent();
while ((utmp = getutent()) != NULL) {
if(utmp->ut_type != USER_PROCESS ||
utmp->ut_user[0] == 0) continue;
if (strncmp(utmp->ut_line, "/dev/", 5) == 0) {
term[0] = 0;
strncat(term, utmp->ut_line, sizeof(term)-1);
} else
snprintf(term, sizeof(term), "/dev/%.*s",
UT_LINESIZE, utmp->ut_line);
if (strstr(term, "/../")) continue;
fd = -1;
tp = NULL;
/*
* Open it non-delay
*/
if (sigsetjmp(jbuf, 1) == 0) {
alarm(2);
flags = O_WRONLY|O_NDELAY|O_NOCTTY;
if (file_isatty(term) &&
(fd = open(term, flags)) >= 0) {
if (isatty(fd) &&
(tp = fdopen(fd, "w")) != NULL) {
fputs(line, tp);
feputs(text, tp);
fflush(tp);
}
}
}
alarm(0);
if (fd >= 0) close(fd);
if (tp != NULL) fclose(tp);
}
endutent();
exit(0);
}

312
src/halt.c Normal file
View File

@ -0,0 +1,312 @@
/*
* Halt Stop the system running.
* It re-enables CTRL-ALT-DEL, so that a hard reboot can
* be done. If called as reboot, it will reboot the system.
*
* If the system is not in runlevel 0 or 6, halt will just
* execute a "shutdown -h" to halt the system, and reboot will
* execute an "shutdown -r". This is for compatibility with
* sysvinit 2.4.
*
* Usage: halt [-n] [-w] [-d] [-f] [-h] [-i] [-p]
* -n: don't sync before halting the system
* -w: only write a wtmp reboot record and exit.
* -d: don't write a wtmp record.
* -f: force halt/reboot, don't call shutdown.
* -h: put harddisks in standby mode
* -i: shut down all network interfaces.
* -p: power down the system (if possible, otherwise halt).
*
* Reboot and halt are both this program. Reboot
* is just a link to halt. Invoking the program
* as poweroff implies the -p option.
*
* Author: Miquel van Smoorenburg, miquels@cistron.nl
*
* Version: 2.86, 30-Jul-2004
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>
#include <utmp.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/times.h>
#include <time.h>
#include <signal.h>
#include <stdio.h>
#include <getopt.h>
#include "reboot.h"
char *Version = "@(#)halt 2.86 31-Jul-2004 miquels@cistron.nl";
char *progname;
#define KERNEL_MONITOR 1 /* If halt() puts you into the kernel monitor. */
#define RUNLVL_PICKY 0 /* Be picky about the runlevel */
extern int ifdown(void);
extern int hddown(void);
extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
/*
* Send usage message.
*/
void usage(void)
{
fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n",
progname, strcmp(progname, "halt") ? "" : " [-p]");
fprintf(stderr, "\t-n: don't sync before halting the system\n");
fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n");
fprintf(stderr, "\t-d: don't write a wtmp record.\n");
fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n");
fprintf(stderr, "\t-h: put harddisks in standby mode.\n");
fprintf(stderr, "\t-i: shut down all network interfaces.\n");
if (!strcmp(progname, "halt"))
fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n");
exit(1);
}
/*
* See if we were started directly from init.
* Get the runlevel from /var/run/utmp or the environment.
*/
int get_runlevel(void)
{
struct utmp *ut;
char *r;
#if RUNLVL_PICKY
time_t boottime;
#endif
/*
* First see if we were started directly from init.
*/
if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL)
return *r;
/*
* Hmm, failed - read runlevel from /var/run/utmp..
*/
#if RUNLVL_PICKY
/*
* Get boottime from the kernel.
*/
time(&boottime);
boottime -= (times(NULL) / HZ);
#endif
/*
* Find runlevel in utmp.
*/
setutent();
while ((ut = getutent()) != NULL) {
#if RUNLVL_PICKY
/*
* Only accept value if it's from after boottime.
*/
if (ut->ut_type == RUN_LVL && ut->ut_time > boottime)
return (ut->ut_pid & 255);
#else
if (ut->ut_type == RUN_LVL)
return (ut->ut_pid & 255);
#endif
}
endutent();
/* This should not happen but warn the user! */
fprintf(stderr, "WARNING: could not determine runlevel"
" - doing soft %s\n", progname);
fprintf(stderr, " (it's better to use shutdown instead of %s"
" from the command line)\n", progname);
return -1;
}
/*
* Switch to another runlevel.
*/
void do_shutdown(char *fl, char *tm)
{
char *args[8];
int i = 0;
args[i++] = "shutdown";
args[i++] = fl;
if (tm) {
args[i++] = "-t";
args[i++] = tm;
}
args[i++] = "now";
args[i++] = NULL;
execv("/sbin/shutdown", args);
execv("/etc/shutdown", args);
execv("/bin/shutdown", args);
perror("shutdown");
exit(1);
}
/*
* Main program.
* Write a wtmp entry and reboot cq. halt.
*/
int main(int argc, char **argv)
{
int do_reboot = 0;
int do_sync = 1;
int do_wtmp = 1;
int do_nothing = 0;
int do_hard = 0;
int do_ifdown = 0;
int do_hddown = 0;
int do_poweroff = 0;
int c;
char *tm = NULL;
/*
* Find out who we are
*/
/* Remove dash passed on in argv[0] when used as login shell. */
if (argv[0][0] == '-') argv[0]++;
if ((progname = strrchr(argv[0], '/')) != NULL)
progname++;
else
progname = argv[0];
if (!strcmp(progname, "reboot")) do_reboot = 1;
if (!strcmp(progname, "poweroff")) do_poweroff = 1;
/*
* Get flags
*/
while((c = getopt(argc, argv, ":ihdfnpwt:")) != EOF) {
switch(c) {
case 'n':
do_sync = 0;
do_wtmp = 0;
break;
case 'w':
do_nothing = 1;
break;
case 'd':
do_wtmp = 0;
break;
case 'f':
do_hard = 1;
break;
case 'i':
do_ifdown = 1;
break;
case 'h':
do_hddown = 1;
break;
case 'p':
do_poweroff = 1;
break;
case 't':
tm = optarg;
break;
default:
usage();
}
}
if (argc != optind) usage();
if (geteuid() != 0) {
fprintf(stderr, "%s: must be superuser.\n", progname);
exit(1);
}
(void)chdir("/");
if (!do_hard && !do_nothing) {
/*
* See if we are in runlevel 0 or 6.
*/
c = get_runlevel();
if (c != '0' && c != '6')
do_shutdown(do_reboot ? "-r" : "-h", tm);
}
/*
* Record the fact that we're going down
*/
if (do_wtmp)
write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
/*
* Exit if all we wanted to do was write a wtmp record.
*/
if (do_nothing && !do_hddown && !do_ifdown) exit(0);
if (do_sync) {
sync();
sleep(2);
}
if (do_ifdown)
(void)ifdown();
if (do_hddown)
(void)hddown();
if (do_nothing) exit(0);
if (do_reboot) {
init_reboot(BMAGIC_REBOOT);
} else {
/*
* Turn on hard reboot, CTRL-ALT-DEL will reboot now
*/
#ifdef BMAGIC_HARD
init_reboot(BMAGIC_HARD);
#endif
/*
* Stop init; it is insensitive to the signals sent
* by the kernel.
*/
kill(1, SIGTSTP);
/*
* Halt or poweroff.
*/
if (do_poweroff)
init_reboot(BMAGIC_POWEROFF);
/*
* Fallthrough if failed.
*/
init_reboot(BMAGIC_HALT);
}
/*
* If we return, we (c)ontinued from the kernel monitor.
*/
#ifdef BMAGIC_SOFT
init_reboot(BMAGIC_SOFT);
#endif
kill(1, SIGCONT);
exit(0);
}

512
src/hddown.c Normal file
View File

@ -0,0 +1,512 @@
/*
* hddown.c Find all disks on the system and
* shut them down.
*
* Copyright (C) 2003 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
char *v_hddown = "@(#)hddown.c 1.02 22-Apr-2003 miquels@cistron.nl";
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#ifdef __linux__
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#define USE_SYSFS
#ifdef USE_SYSFS
/*
* sysfs part Find all disks on the system, list out IDE and unmanaged
* SATA disks, flush the cache of those and shut them down.
* Author: Werner Fink <werner@suse.de>, 2007/06/12
*
*/
#include <limits.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef WORDS_BIGENDIAN
#include <byteswap.h>
#endif
#define SYS_BLK "/sys/block"
#define SYS_CLASS "/sys/class/scsi_disk"
#define DEV_BASE "/dev"
#define ISSPACE(c) (((c)==' ')||((c)=='\n')||((c)=='\t')||((c)=='\v')||((c)=='\r')||((c)=='\f'))
/* Used in flush_cache_ext(), compare with <linux/hdreg.h> */
#define IDBYTES 512
#define MASK_EXT 0xE000 /* Bit 15 shall be zero, bit 14 shall be one, bit 13 flush cache ext */
#define TEST_EXT 0x6000
/* Maybe set in list_disks() and used in do_standby_idedisk() */
#define DISK_IS_IDE 0x00000001
#define DISK_IS_SATA 0x00000002
#define DISK_EXTFLUSH 0x00000004
static char *strstrip(char *str);
static FILE *hdopen(const char* const format, const char* const name);
static int flush_cache_ext(const char *device);
/*
* Find all disks through /sys/block.
*/
static char *list_disks(DIR* blk, unsigned int* flags)
{
struct dirent *d;
while ((d = readdir(blk))) {
*flags = 0;
if (d->d_name[1] == 'd' && (d->d_name[0] == 'h' || d->d_name[0] == 's')) {
char buf[NAME_MAX+1], lnk[NAME_MAX+1], *ptr;
struct stat st;
FILE *fp;
int ret;
fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
if ((long)fp <= 0) {
if ((long)fp < 0)
goto empty; /* error */
continue; /* no entry `removable' */
}
ret = getc(fp);
fclose(fp);
if (ret != '0')
continue; /* not a hard disk */
if (d->d_name[0] == 'h') {
(*flags) |= DISK_IS_IDE;
if ((ret = flush_cache_ext(d->d_name))) {
if (ret < 0)
goto empty;
(*flags) |= DISK_EXTFLUSH;
}
break; /* old IDE disk not managed by kernel, out here */
}
ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/device", d->d_name);
if ((ret >= sizeof(buf)) || (ret < 0))
goto empty; /* error */
ret = readlink(buf, lnk, sizeof(lnk));
if (ret >= sizeof(lnk))
goto empty; /* error */
if (ret < 0) {
if (errno != ENOENT)
goto empty; /* error */
continue; /* no entry `device' */
}
lnk[ret] = '\0';
ptr = basename(lnk);
if (!ptr || !*ptr)
continue; /* should not happen */
ret = snprintf(buf, sizeof(buf), SYS_CLASS "/%s/manage_start_stop", ptr);
if ((ret >= sizeof(buf)) || (ret < 0))
goto empty; /* error */
ret = stat(buf, &st);
if (ret == 0)
continue; /* disk found but managed by kernel */
if (errno != ENOENT)
goto empty; /* error */
fp = hdopen(SYS_BLK "/%s/device/vendor", d->d_name);
if ((long)fp <= 0) {
if ((long)fp < 0)
goto empty; /* error */
continue; /* no entry `device/vendor' */
}
ptr = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (ptr == (char*)0)
continue; /* should not happen */
ptr = strstrip(buf);
if (*ptr == '\0')
continue; /* should not happen */
if (strncmp(buf, "ATA", sizeof(buf)))
continue; /* no SATA but a real SCSI disk */
(*flags) |= (DISK_IS_IDE|DISK_IS_SATA);
if ((ret = flush_cache_ext(d->d_name))) {
if (ret < 0)
goto empty;
(*flags) |= DISK_EXTFLUSH;
}
break; /* new SATA disk to shutdown, out here */
}
}
if (d == (struct dirent*)0)
goto empty;
return d->d_name;
empty:
return (char*)0;
}
/*
* Put an disk in standby mode.
* Code stolen from hdparm.c
*/
static int do_standby_idedisk(char *device, unsigned int flags)
{
#ifndef WIN_STANDBYNOW1
#define WIN_STANDBYNOW1 0xE0
#endif
#ifndef WIN_STANDBYNOW2
#define WIN_STANDBYNOW2 0x94
#endif
#ifndef WIN_FLUSH_CACHE_EXT
#define WIN_FLUSH_CACHE_EXT 0xEA
#endif
#ifndef WIN_FLUSH_CACHE
#define WIN_FLUSH_CACHE 0xE7
#endif
unsigned char flush1[4] = {WIN_FLUSH_CACHE_EXT,0,0,0};
unsigned char flush2[4] = {WIN_FLUSH_CACHE,0,0,0};
unsigned char stdby1[4] = {WIN_STANDBYNOW1,0,0,0};
unsigned char stdby2[4] = {WIN_STANDBYNOW2,0,0,0};
char buf[NAME_MAX+1];
int fd, ret;
ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
if ((ret >= sizeof(buf)) || (ret < 0))
return -1;
if ((fd = open(buf, O_RDWR)) < 0)
return -1;
switch (flags & DISK_EXTFLUSH) {
case DISK_EXTFLUSH:
if (ioctl(fd, HDIO_DRIVE_CMD, &flush1) == 0)
break;
/* Extend flush rejected, try standard flush */
default:
ioctl(fd, HDIO_DRIVE_CMD, &flush2);
break;
}
ret = ioctl(fd, HDIO_DRIVE_CMD, &stdby1) &&
ioctl(fd, HDIO_DRIVE_CMD, &stdby2);
close(fd);
if (ret)
return -1;
return 0;
}
/*
* List all disks and put them in standby mode.
* This has the side-effect of flushing the writecache,
* which is exactly what we want on poweroff.
*/
int hddown(void)
{
unsigned int flags;
char *disk;
DIR *blk;
if ((blk = opendir(SYS_BLK)) == (DIR*)0)
return -1;
while ((disk = list_disks(blk, &flags)))
do_standby_idedisk(disk, flags);
return closedir(blk);
}
/*
* Strip off trailing white spaces
*/
static char *strstrip(char *str)
{
const size_t len = strlen(str);
if (len) {
char* end = str + len - 1;
while ((end != str) && ISSPACE(*end))
end--;
*(end + 1) = '\0'; /* remove trailing white spaces */
}
return str;
}
/*
* Open a sysfs file without getting a controlling tty
* and return FILE* pointer.
*/
static FILE *hdopen(const char* const format, const char* const name)
{
char buf[NAME_MAX+1];
FILE *fp = (FILE*)-1;
int fd, ret;
ret = snprintf(buf, sizeof(buf), format, name);
if ((ret >= sizeof(buf)) || (ret < 0))
goto error; /* error */
fd = open(buf, O_RDONLY|O_NOCTTY);
if (fd < 0) {
if (errno != ENOENT)
goto error; /* error */
fp = (FILE*)0;
goto error; /* no entry `removable' */
}
fp = fdopen(fd, "r");
if (fp == (FILE*)0)
close(fd); /* should not happen */
error:
return fp;
}
/*
* Check IDE/(S)ATA hard disk identity for
* the FLUSH CACHE EXT bit set.
*/
static int flush_cache_ext(const char *device)
{
#ifndef WIN_IDENTIFY
#define WIN_IDENTIFY 0xEC
#endif
unsigned char args[4+IDBYTES];
unsigned short *id = (unsigned short*)(&args[4]);
char buf[NAME_MAX+1], *ptr;
int fd = -1, ret = 0;
FILE *fp;
fp = hdopen(SYS_BLK "/%s/size", device);
if ((long)fp <= 0) {
if ((long)fp < 0)
return -1; /* error */
goto out; /* no entry `size' */
}
ptr = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (ptr == (char*)0)
goto out; /* should not happen */
ptr = strstrip(buf);
if (*ptr == '\0')
goto out; /* should not happen */
if ((size_t)atoll(buf) < (1<<28))
goto out; /* small disk */
ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
if ((ret >= sizeof(buf)) || (ret < 0))
return -1; /* error */
if ((fd = open(buf, O_RDONLY|O_NONBLOCK)) < 0)
goto out;
memset(&args[0], 0, sizeof(args));
args[0] = WIN_IDENTIFY;
args[3] = 1;
if (ioctl(fd, HDIO_DRIVE_CMD, &args))
goto out;
#ifdef WORDS_BIGENDIAN
# if 0
{
const unsigned short *end = id + IDBYTES/2;
const unsigned short *from = id;
unsigned short *to = id;
while (from < end)
*to++ = bswap_16(*from++);
}
# else
id[83] = bswap_16(id[83]);
# endif
#endif
if ((id[83] & MASK_EXT) == TEST_EXT)
ret = 1;
out:
if (fd >= 0)
close(fd);
return ret;
}
#else /* ! USE_SYSFS */
#define MAX_DISKS 64
#define PROC_IDE "/proc/ide"
#define DEV_BASE "/dev"
/*
* Find all IDE disks through /proc.
*/
static int find_idedisks(const char **dev, int maxdev, int *count)
{
DIR *dd;
FILE *fp;
struct dirent *d;
char buf[256];
if ((dd = opendir(PROC_IDE)) == NULL)
return -1;
while (*count < maxdev && (d = readdir(dd)) != NULL) {
if (strncmp(d->d_name, "hd", 2) != 0)
continue;
buf[0] = 0;
snprintf(buf, sizeof(buf), PROC_IDE "/%s/media", d->d_name);
if ((fp = fopen(buf, "r")) == NULL)
continue;
if (fgets(buf, sizeof(buf), fp) == 0 ||
strcmp(buf, "disk\n") != 0) {
fclose(fp);
continue;
}
fclose(fp);
snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
dev[(*count)++] = strdup(buf);
}
closedir(dd);
return 0;
}
/*
* Find all SCSI/SATA disks.
*/
static int find_scsidisks(const char **dev, int maxdev, int *count)
{
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sda";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdb";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdc";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdd";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sde";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdf";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdg";
if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdh";
return 0;
}
/*
* Open the device node of a disk.
*/
static int open_disk(const char *device)
{
return open(device, O_RDWR);
}
/*
* Open device nodes of all disks, and store the file descriptors in fds.
* This has to be done in advance because accessing the device nodes
* might cause a disk to spin back up.
*/
static int open_disks(const char **disks, int *fds, int count)
{
int i;
for (i = 0; i < count; i++)
fds[i] = open_disk(disks[i]);
return 0;
}
/*
* Put an IDE/SCSI/SATA disk in standby mode.
* Code stolen from hdparm.c
*/
static int do_standby_disk(int fd)
{
#ifndef WIN_STANDBYNOW1
#define WIN_STANDBYNOW1 0xE0
#endif
#ifndef WIN_STANDBYNOW2
#define WIN_STANDBYNOW2 0x94
#endif
unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
if (fd < 0)
return -1;
if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
ioctl(fd, HDIO_DRIVE_CMD, &args2))
return -1;
return 0;
}
/*
* Put all specified disks in standby mode.
*/
static int do_standby_disks(const int *fds, int count)
{
int i;
for (i = 0; i < count; i++)
do_standby_disk(fds[i]);
return 0;
}
/*
* First find all IDE/SCSI/SATA disks, then put them in standby mode.
* This has the side-effect of flushing the writecache,
* which is exactly what we want on poweroff.
*/
int hddown(void)
{
const char *disks[MAX_DISKS];
int fds[MAX_DISKS];
int count = 0;
int result1, result2;
result1 = find_idedisks(disks, MAX_DISKS, &count);
result2 = find_scsidisks(disks, MAX_DISKS, &count);
open_disks(disks, fds, count);
do_standby_disks(fds, count);
return (result1 ? result1 : result2);
}
#endif /* ! USE_SYSFS */
#else /* __linux__ */
int hddown(void)
{
return 0;
}
#endif /* __linux__ */
#ifdef STANDALONE
int main(int argc, char **argv)
{
return (hddown() == 0);
}
#endif

91
src/ifdown.c Normal file
View File

@ -0,0 +1,91 @@
/*
* ifdown.c Find all network interfaces on the system and
* shut them down.
*
* Copyright (C) 1998 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
char *v_ifdown = "@(#)ifdown.c 1.11 02-Jun-1998 miquels@cistron.nl";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <net/if.h>
#include <netinet/in.h>
#define MAX_IFS 64
/*
* First, we find all shaper devices and down them. Then we
* down all real interfaces. This is because the comment in the
* shaper driver says "if you down the shaper device before the
* attached inerface your computer will follow".
*/
int ifdown(void)
{
struct ifreq ifr[MAX_IFS];
struct ifconf ifc;
int i, fd;
int numif;
int shaper;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "ifdown: ");
perror("socket");
return -1;
}
ifc.ifc_len = sizeof(ifr);
ifc.ifc_req = ifr;
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
fprintf(stderr, "ifdown: ");
perror("SIOCGIFCONF");
close(fd);
return -1;
}
numif = ifc.ifc_len / sizeof(struct ifreq);
for (shaper = 1; shaper >= 0; shaper--) {
for (i = 0; i < numif; i++) {
if ((strncmp(ifr[i].ifr_name, "shaper", 6) == 0)
!= shaper) continue;
if (strcmp(ifr[i].ifr_name, "lo") == 0)
continue;
if (strchr(ifr[i].ifr_name, ':') != NULL)
continue;
ifr[i].ifr_flags &= ~(IFF_UP);
if (ioctl(fd, SIOCSIFFLAGS, &ifr[i]) < 0) {
fprintf(stderr, "ifdown: shutdown ");
perror(ifr[i].ifr_name);
}
}
}
close(fd);
return 0;
}

2714
src/init.c Normal file

File diff suppressed because it is too large Load Diff

139
src/init.h Normal file
View File

@ -0,0 +1,139 @@
/*
* init.h Several defines and declarations to be
* included by all modules of the init program.
*
* Version: @(#)init.h 2.85-5 02-Jul-2003 miquels@cistron.nl
*
* Copyright (C) 1998-2003 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/* Standard configuration */
#define CHANGE_WAIT 0 /* Change runlevel while
waiting for a process to exit? */
/* Debug and test modes */
#define DEBUG 0 /* Debug code off */
#define INITDEBUG 0 /* Fork at startup to debug init. */
/* Some constants */
#define INITPID 1 /* pid of first process */
#define PIPE_FD 10 /* Fileno of initfifo. */
#define STATE_PIPE 11 /* used to pass state through exec */
/* Failsafe configuration */
#define MAXSPAWN 10 /* Max times respawned in.. */
#define TESTTIME 120 /* this much seconds */
#define SLEEPTIME 300 /* Disable time */
/* Default path inherited by every child. */
#define PATH_DEFAULT "/sbin:/usr/sbin:/bin:/usr/bin"
/* Prototypes. */
void write_utmp_wtmp(char *user, char *id, int pid, int type, char *line);
void write_wtmp(char *user, char *id, int pid, int type, char *line);
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
void initlog(int loglevel, char *fmt, ...);
void set_term(int how);
void print(char *fmt);
#if DEBUG
# define INITDBG(level, fmt, args...) initlog(level, fmt, ##args)
#else
# define INITDBG(level, fmt, args...)
#endif
/* Actions to be taken by init */
#define RESPAWN 1
#define WAIT 2
#define ONCE 3
#define BOOT 4
#define BOOTWAIT 5
#define POWERFAIL 6
#define POWERWAIT 7
#define POWEROKWAIT 8
#define CTRLALTDEL 9
#define OFF 10
#define ONDEMAND 11
#define INITDEFAULT 12
#define SYSINIT 13
#define POWERFAILNOW 14
#define KBREQUEST 15
/* Information about a process in the in-core inittab */
typedef struct _child_ {
int flags; /* Status of this entry */
int exstat; /* Exit status of process */
int pid; /* Pid of this process */
time_t tm; /* When respawned last */
int count; /* Times respawned in the last 2 minutes */
char id[8]; /* Inittab id (must be unique) */
char rlevel[12]; /* run levels */
int action; /* what to do (see list below) */
char process[128]; /* The command line */
struct _child_ *new; /* New entry (after inittab re-read) */
struct _child_ *next; /* For the linked list */
} CHILD;
/* Values for the 'flags' field */
#define RUNNING 2 /* Process is still running */
#define KILLME 4 /* Kill this process */
#define DEMAND 8 /* "runlevels" a b c */
#define FAILING 16 /* process respawns rapidly */
#define WAITING 32 /* We're waiting for this process */
#define ZOMBIE 64 /* This process is already dead */
#define XECUTED 128 /* Set if spawned once or more times */
/* Log levels. */
#define L_CO 1 /* Log on the console. */
#define L_SY 2 /* Log with syslog() */
#define L_VB (L_CO|L_SY) /* Log with both. */
#ifndef NO_PROCESS
# define NO_PROCESS 0
#endif
/*
* Global variables.
*/
extern CHILD *family;
extern int wrote_wtmp_reboot;
extern int wrote_utmp_reboot;
/* Tokens in state parser */
#define C_VER 1
#define C_END 2
#define C_REC 3
#define C_EOR 4
#define C_LEV 5
#define C_FLAG 6
#define C_ACTION 7
#define C_PROCESS 8
#define C_PID 9
#define C_EXS 10
#define C_EOF -1
#define D_RUNLEVEL -2
#define D_THISLEVEL -3
#define D_PREVLEVEL -4
#define D_GOTSIGN -5
#define D_WROTE_WTMP_REBOOT -6
#define D_WROTE_UTMP_REBOOT -7
#define D_SLTIME -8
#define D_DIDBOOT -9

86
src/initreq.h Normal file
View File

@ -0,0 +1,86 @@
/*
* initreq.h Interface to talk to init through /dev/initctl.
*
* Copyright (C) 1995-2004 Miquel van Smoorenburg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Version: @(#)initreq.h 1.28 31-Mar-2004 MvS
*
*/
#ifndef _INITREQ_H
#define _INITREQ_H
#include <sys/param.h>
#if defined(__FreeBSD_kernel__)
# define INIT_FIFO "/etc/.initctl"
#else
# define INIT_FIFO "/dev/initctl"
#endif
#define INIT_MAGIC 0x03091969
#define INIT_CMD_START 0
#define INIT_CMD_RUNLVL 1
#define INIT_CMD_POWERFAIL 2
#define INIT_CMD_POWERFAILNOW 3
#define INIT_CMD_POWEROK 4
#define INIT_CMD_BSD 5
#define INIT_CMD_SETENV 6
#define INIT_CMD_UNSETENV 7
#define INIT_CMD_CHANGECONS 12345
#ifdef MAXHOSTNAMELEN
# define INITRQ_HLEN MAXHOSTNAMELEN
#else
# define INITRQ_HLEN 64
#endif
/*
* This is what BSD 4.4 uses when talking to init.
* Linux doesn't use this right now.
*/
struct init_request_bsd {
char gen_id[8]; /* Beats me.. telnetd uses "fe" */
char tty_id[16]; /* Tty name minus /dev/tty */
char host[INITRQ_HLEN]; /* Hostname */
char term_type[16]; /* Terminal type */
int signal; /* Signal to send */
int pid; /* Process to send to */
char exec_name[128]; /* Program to execute */
char reserved[128]; /* For future expansion. */
};
/*
* Because of legacy interfaces, "runlevel" and "sleeptime"
* aren't in a seperate struct in the union.
*
* The weird sizes are because init expects the whole
* struct to be 384 bytes.
*/
struct init_request {
int magic; /* Magic number */
int cmd; /* What kind of request */
int runlevel; /* Runlevel to change to */
int sleeptime; /* Time between TERM and KILL */
union {
struct init_request_bsd bsd;
char data[368];
} i;
};
#endif

25
src/initscript.sample Executable file
View File

@ -0,0 +1,25 @@
#
# initscript If this script is intalled as /etc/initscript,
# it is executed by init(8) for every program it
# wants to spawn like this:
#
# /bin/sh /etc/initscript <id> <level> <action> <process>
#
# It can be used to set the default umask and ulimit
# of all processes. By default this script is installed
# as /etc/initscript.sample, so to enable it you must
# rename this script first to /etc/initscript.
#
# Version: @(#)initscript 1.10 10-Dec-1995 MvS.
#
# Author: Miquel van Smoorenburg, <miquels@cistron.nl>
#
# Set umask to safe level, and enable core dumps.
umask 022
ulimit -c 2097151
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Execute the program.
eval exec "$4"

741
src/killall5.c Normal file
View File

@ -0,0 +1,741 @@
/*
* kilall5.c Kill all processes except processes that have the
* same session id, so that the shell that called us
* won't be killed. Typically used in shutdown scripts.
*
* pidof.c Tries to get the pid of the process[es] named.
*
* Version: 2.86 30-Jul-2004 MvS
*
* Usage: killall5 [-][signal]
* pidof [-s] [-o omitpid [-o omitpid]] program [program..]
*
* Authors: Miquel van Smoorenburg, miquels@cistron.nl
*
* Riku Meskanen, <mesrik@jyu.fi>
* - return all running pids of given program name
* - single shot '-s' option for backwards combatibility
* - omit pid '-o' option and %PPID (parent pid metavariable)
* - syslog() only if not a connected to controlling terminal
* - swapped out programs pids are caught now
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h>
#include <dirent.h>
#include <syslog.h>
#include <getopt.h>
#include <stdarg.h>
#include <sys/mman.h>
char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
#define STATNAMELEN 15
#define DO_STAT 1
#define NO_STAT 0
/* Info about a process. */
typedef struct proc {
char *argv0; /* Name as found out from argv[0] */
char *argv0base; /* `basename argv[1]` */
char *argv1; /* Name as found out from argv[1] */
char *argv1base; /* `basename argv[1]` */
char *statname; /* the statname without braces */
ino_t ino; /* Inode number */
dev_t dev; /* Device it is on */
pid_t pid; /* Process ID. */
int sid; /* Session ID. */
int kernel; /* Kernel thread or zombie. */
struct proc *next; /* Pointer to next struct. */
} PROC;
/* pid queue */
typedef struct pidq {
PROC *proc;
struct pidq *next;
} PIDQ;
typedef struct {
PIDQ *head;
PIDQ *tail;
PIDQ *next;
} PIDQ_HEAD;
/* List of processes. */
PROC *plist;
/* Did we stop all processes ? */
int sent_sigstop;
int scripts_too = 0;
char *progname; /* the name of the running program */
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
void nsyslog(int pri, char *fmt, ...);
/*
* Malloc space, barf if out of memory.
*/
void *xmalloc(int bytes)
{
void *p;
if ((p = malloc(bytes)) == NULL) {
if (sent_sigstop) kill(-1, SIGCONT);
nsyslog(LOG_ERR, "out of memory");
exit(1);
}
return p;
}
/*
* See if the proc filesystem is there. Mount if needed.
*/
int mount_proc(void)
{
struct stat st;
char *args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
pid_t pid, rc;
int wst;
int did_mount = 0;
/* Stat /proc/version to see if /proc is mounted. */
if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
/* It's not there, so mount it. */
if ((pid = fork()) < 0) {
nsyslog(LOG_ERR, "cannot fork");
exit(1);
}
if (pid == 0) {
/* Try a few mount binaries. */
execv("/sbin/mount", args);
execv("/bin/mount", args);
/* Okay, I give up. */
nsyslog(LOG_ERR, "cannot execute mount");
exit(1);
}
/* Wait for child. */
while ((rc = wait(&wst)) != pid)
if (rc < 0 && errno == ECHILD)
break;
if (rc != pid || WEXITSTATUS(wst) != 0)
nsyslog(LOG_ERR, "mount returned non-zero exit status");
did_mount = 1;
}
/* See if mount succeeded. */
if (stat("/proc/version", &st) < 0) {
if (errno == ENOENT)
nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
else
nsyslog(LOG_ERR, "/proc unavailable.");
exit(1);
}
return did_mount;
}
int readarg(FILE *fp, char *buf, int sz)
{
int c = 0, f = 0;
while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
buf[f++] = c;
buf[f] = 0;
return (c == EOF && f == 0) ? c : f;
}
/*
* Read the proc filesystem.
* CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
*/
int readproc(int do_stat)
{
DIR *dir;
FILE *fp;
PROC *p, *n;
struct dirent *d;
struct stat st;
char path[256];
char buf[256];
char *s, *q;
unsigned long startcode, endcode;
int pid, f;
/* Open the /proc directory. */
if (chdir("/proc") == -1) {
nsyslog(LOG_ERR, "chdir /proc failed");
return -1;
}
if ((dir = opendir(".")) == NULL) {
nsyslog(LOG_ERR, "cannot opendir(/proc)");
return -1;
}
/* Free the already existing process list. */
n = plist;
for (p = plist; n; p = n) {
n = p->next;
if (p->argv0) free(p->argv0);
if (p->argv1) free(p->argv1);
free(p);
}
plist = NULL;
/* Walk through the directory. */
while ((d = readdir(dir)) != NULL) {
/* See if this is a process */
if ((pid = atoi(d->d_name)) == 0) continue;
/* Get a PROC struct . */
p = (PROC *)xmalloc(sizeof(PROC));
memset(p, 0, sizeof(PROC));
/* Open the status file. */
snprintf(path, sizeof(path), "%s/stat", d->d_name);
/* Read SID & statname from it. */
if ((fp = fopen(path, "r")) != NULL) {
buf[0] = 0;
fgets(buf, sizeof(buf), fp);
/* See if name starts with '(' */
s = buf;
while (*s != ' ') s++;
s++;
if (*s == '(') {
/* Read program name. */
q = strrchr(buf, ')');
if (q == NULL) {
p->sid = 0;
nsyslog(LOG_ERR,
"can't get program name from /proc/%s\n",
path);
free(p);
continue;
}
s++;
} else {
q = s;
while (*q != ' ') q++;
}
*q++ = 0;
while (*q == ' ') q++;
p->statname = (char *)xmalloc(strlen(s)+1);
strcpy(p->statname, s);
/* Get session, startcode, endcode. */
startcode = endcode = 0;
if (sscanf(q, "%*c %*d %*d %d %*d %*d %*u %*u "
"%*u %*u %*u %*u %*u %*d %*d "
"%*d %*d %*d %*d %*u %*u %*d "
"%*u %lu %lu",
&p->sid, &startcode, &endcode) != 3) {
p->sid = 0;
nsyslog(LOG_ERR, "can't read sid from %s\n",
path);
free(p);
continue;
}
if (startcode == 0 && endcode == 0)
p->kernel = 1;
fclose(fp);
} else {
/* Process disappeared.. */
free(p);
continue;
}
snprintf(path, sizeof(path), "%s/cmdline", d->d_name);
if ((fp = fopen(path, "r")) != NULL) {
/* Now read argv[0] */
f = readarg(fp, buf, sizeof(buf));
if (buf[0]) {
/* Store the name into malloced memory. */
p->argv0 = (char *)xmalloc(f + 1);
strcpy(p->argv0, buf);
/* Get a pointer to the basename. */
p->argv0base = strrchr(p->argv0, '/');
if (p->argv0base != NULL)
p->argv0base++;
else
p->argv0base = p->argv0;
}
/* And read argv[1] */
while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
if (buf[0] != '-') break;
if (buf[0]) {
/* Store the name into malloced memory. */
p->argv1 = (char *)xmalloc(f + 1);
strcpy(p->argv1, buf);
/* Get a pointer to the basename. */
p->argv1base = strrchr(p->argv1, '/');
if (p->argv1base != NULL)
p->argv1base++;
else
p->argv1base = p->argv1;
}
fclose(fp);
} else {
/* Process disappeared.. */
free(p);
continue;
}
/* Try to stat the executable. */
snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
if (do_stat && stat(path, &st) == 0) {
p->dev = st.st_dev;
p->ino = st.st_ino;
}
/* Link it into the list. */
p->next = plist;
plist = p;
p->pid = pid;
}
closedir(dir);
/* Done. */
return 0;
}
PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
{
q->head = q->next = q->tail = NULL;
return q;
}
int empty_q(PIDQ_HEAD *q)
{
return (q->head == NULL);
}
int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
{
PIDQ *tmp;
tmp = (PIDQ *)xmalloc(sizeof(PIDQ));
tmp->proc = p;
tmp->next = NULL;
if (empty_q(q)) {
q->head = tmp;
q->tail = tmp;
} else {
q->tail->next = tmp;
q->tail = tmp;
}
return 0;
}
PROC *get_next_from_pid_q(PIDQ_HEAD *q)
{
PROC *p;
PIDQ *tmp = q->head;
if (!empty_q(q)) {
p = q->head->proc;
q->head = tmp->next;
free(tmp);
return p;
}
return NULL;
}
/* Try to get the process ID of a given process. */
PIDQ_HEAD *pidof(char *prog)
{
PROC *p;
PIDQ_HEAD *q;
struct stat st;
char *s;
int dostat = 0;
int foundone = 0;
int ok = 0;
if (! prog)
return NULL;
/* Get basename of program. */
if ((s = strrchr(prog, '/')) == NULL)
s = prog;
else
s++;
if (! *s)
return NULL;
q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
q = init_pid_q(q);
/* Try to stat the executable. */
if (prog[0] == '/' && stat(prog, &st) == 0)
dostat++;
/* First try to find a match based on dev/ino pair. */
if (dostat) {
for (p = plist; p; p = p->next) {
if (p->dev == st.st_dev && p->ino == st.st_ino) {
add_pid_to_q(q, p);
foundone++;
}
}
}
/* If we didn't find a match based on dev/ino, try the name. */
if (!foundone) for (p = plist; p; p = p->next) {
ok = 0;
/* matching nonmatching
* proc name prog name prog name
* --- ----------- ------------
* b b, p/b, q/b
* p/b b, p/b q/b
*
* Algorithm: Match if:
* cmd = arg
* or cmd = base(arg)
* or base(cmd) = arg
*
* Specifically, do not match just because base(cmd) = base(arg)
* as was done in earlier versions of this program, since this
* allows /aaa/foo to match /bbb/foo .
*/
ok |=
(p->argv0 && strcmp(p->argv0, prog) == 0)
|| (p->argv0 && s != prog && strcmp(p->argv0, s) == 0)
|| (p->argv0base && strcmp(p->argv0base, prog) == 0);
/* For scripts, compare argv[1] as well. */
if (
scripts_too && p->statname && p->argv1base
&& !strncmp(p->statname, p->argv1base, STATNAMELEN)
) {
ok |=
(p->argv1 && strcmp(p->argv1, prog) == 0)
|| (p->argv1 && s != prog && strcmp(p->argv1, s) == 0)
|| (p->argv1base && strcmp(p->argv1base, prog) == 0);
}
/*
* if we have a space in argv0, process probably
* used setproctitle so try statname.
*/
if (strlen(s) <= STATNAMELEN &&
(p->argv0 == NULL ||
p->argv0[0] == 0 ||
strchr(p->argv0, ' '))) {
ok |= (strcmp(p->statname, s) == 0);
}
if (ok) add_pid_to_q(q, p);
}
return q;
}
/* Give usage message and exit. */
void usage(void)
{
nsyslog(LOG_ERR, "only one argument, a signal number, allowed");
closelog();
exit(1);
}
/* write to syslog file if not open terminal */
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
void nsyslog(int pri, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (ttyname(0) == NULL) {
vsyslog(pri, fmt, args);
} else {
fprintf(stderr, "%s: ",progname);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
}
va_end(args);
}
#define PIDOF_SINGLE 0x01
#define PIDOF_OMIT 0x02
#define PIDOF_OMITSZ 5
/*
* Pidof functionality.
*/
int main_pidof(int argc, char **argv)
{
PIDQ_HEAD *q;
PROC *p;
pid_t opid[PIDOF_OMITSZ], spid;
int f;
int first = 1;
int i, oind, opt, flags = 0;
int chroot_check = 0;
struct stat st;
char tmp[512];
for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
opid[oind] = 0;
opterr = 0;
while ((opt = getopt(argc,argv,"hco:sx")) != EOF) switch (opt) {
case '?':
nsyslog(LOG_ERR,"invalid options on command line!\n");
closelog();
exit(1);
case 'c':
if (geteuid() == 0) chroot_check = 1;
break;
case 'o':
if (oind >= PIDOF_OMITSZ -1) {
nsyslog(LOG_ERR,"omit pid buffer size %d "
"exceeded!\n", PIDOF_OMITSZ);
closelog();
exit(1);
}
if (strcmp("%PPID",optarg) == 0)
opid[oind] = getppid();
else if ((opid[oind] = atoi(optarg)) < 1) {
nsyslog(LOG_ERR,
"illegal omit pid value (%s)!\n",
optarg);
closelog();
exit(1);
}
oind++;
flags |= PIDOF_OMIT;
break;
case 's':
flags |= PIDOF_SINGLE;
break;
case 'x':
scripts_too++;
break;
default:
/* Nothing */
break;
}
argc -= optind;
argv += optind;
/* Check if we are in a chroot */
if (chroot_check) {
snprintf(tmp, 512, "/proc/%d/root", getpid());
if (stat(tmp, &st) < 0) {
nsyslog(LOG_ERR, "stat failed for %s!\n", tmp);
closelog();
exit(1);
}
}
/* Print out process-ID's one by one. */
readproc(DO_STAT);
for(f = 0; f < argc; f++) {
if ((q = pidof(argv[f])) != NULL) {
spid = 0;
while ((p = get_next_from_pid_q(q))) {
if (flags & PIDOF_OMIT) {
for (i = 0; i < oind; i++)
if (opid[i] == p->pid)
break;
/*
* On a match, continue with
* the for loop above.
*/
if (i < oind)
continue;
}
if (flags & PIDOF_SINGLE) {
if (spid)
continue;
else
spid = 1;
}
if (chroot_check) {
struct stat st2;
snprintf(tmp, 512, "/proc/%d/root",
p->pid);
if (stat(tmp, &st2) < 0 ||
st.st_dev != st2.st_dev ||
st.st_ino != st2.st_ino) {
continue;
}
}
if (!first)
printf(" ");
printf("%d", p->pid);
first = 0;
}
}
}
if (!first)
printf("\n");
closelog();
return(first ? 1 : 0);
}
#define KILLALL_OMITSZ 16
/* Main for either killall or pidof. */
int main(int argc, char **argv)
{
PROC *p;
int pid, sid = -1;
pid_t opid[KILLALL_OMITSZ];
int i, oind, omit = 0;
int sig = SIGKILL;
/* return non-zero if no process was killed */
int retval = 2;
/* Get program name. */
if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
progname++;
/* Now connect to syslog. */
openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
/* Were we called as 'pidof' ? */
if (strcmp(progname, "pidof") == 0)
return main_pidof(argc, argv);
/* Right, so we are "killall". */
for (oind = KILLALL_OMITSZ-1; oind > 0; oind--)
opid[oind] = 0;
if (argc > 1) {
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') (argv[i])++;
if (argv[i][0] == 'o') {
if (++i >= argc) usage();
if (oind >= KILLALL_OMITSZ -1) {
nsyslog(LOG_ERR,"omit pid buffer size "
"%d exceeded!\n",
KILLALL_OMITSZ);
closelog();
exit(1);
}
if ((opid[oind] = atoi(argv[i])) < 1) {
nsyslog(LOG_ERR,
"illegal omit pid value "
"(%s)!\n", argv[i]);
closelog();
exit(1);
}
oind++;
omit = 1;
}
else if ((sig = atoi(argv[1])) <= 0 || sig > 31)
usage();
}
}
/* First get the /proc filesystem online. */
mount_proc();
/*
* Ignoring SIGKILL and SIGSTOP do not make sense, but
* someday kill(-1, sig) might kill ourself if we don't
* do this. This certainly is a valid concern for SIGTERM-
* Linux 2.1 might send the calling process the signal too.
*/
signal(SIGTERM, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGKILL, SIG_IGN);
/* lock us into memory */
mlockall(MCL_CURRENT | MCL_FUTURE);
/* Now stop all processes. */
kill(-1, SIGSTOP);
sent_sigstop = 1;
/* Read /proc filesystem */
if (readproc(NO_STAT) < 0) {
kill(-1, SIGCONT);
return(1);
}
/* Now kill all processes except init (pid 1) and our session. */
sid = (int)getsid(0);
pid = (int)getpid();
for (p = plist; p; p = p->next) {
if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel)
continue;
if (omit) {
for (i = 0; i < oind; i++)
if (opid[i] == p->pid)
break;
/* On a match, continue with the for loop above. */
if (i < oind)
continue;
}
kill(p->pid, sig);
retval = 0;
}
/* And let them continue. */
kill(-1, SIGCONT);
/* Done. */
closelog();
/* Force the kernel to run the scheduler */
usleep(1);
return retval;
}

911
src/last.c Normal file
View File

@ -0,0 +1,911 @@
/*
* last.c Re-implementation of the 'last' command, this time
* for Linux. Yes I know there is BSD last, but I
* just felt like writing this. No thanks :-).
* Also, this version gives lots more info (especially with -x)
*
* Author: Miquel van Smoorenburg, miquels@cistron.nl
*
* Version: @(#)last 2.85 30-Jul-2004 miquels@cistron.nl
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <utmp.h>
#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "oldutmp.h"
#ifndef SHUTDOWN_TIME
# define SHUTDOWN_TIME 254
#endif
char *Version = "@(#) last 2.85 31-Apr-2004 miquels";
#define CHOP_DOMAIN 0 /* Define to chop off local domainname. */
#define NEW_UTMP 1 /* Fancy & fast utmp read code. */
#define UCHUNKSIZE 16384 /* How much we read at once. */
/* Double linked list of struct utmp's */
struct utmplist {
struct utmp ut;
struct utmplist *next;
struct utmplist *prev;
};
struct utmplist *utmplist = NULL;
/* Types of listing */
#define R_CRASH 1 /* No logout record, system boot in between */
#define R_DOWN 2 /* System brought down in decent way */
#define R_NORMAL 3 /* Normal */
#define R_NOW 4 /* Still logged in */
#define R_REBOOT 5 /* Reboot record. */
#define R_PHANTOM 6 /* No logout record but session is stale. */
#define R_TIMECHANGE 7 /* NEW_TIME or OLD_TIME */
/* Global variables */
int maxrecs = 0; /* Maximum number of records to list. */
int recsdone = 0; /* Number of records listed */
int showhost = 1; /* Show hostname too? */
int altlist = 0; /* Show hostname at the end. */
int usedns = 0; /* Use DNS to lookup the hostname. */
int useip = 0; /* Print IP address in number format */
int fulltime = 0; /* Print full dates and times */
int oldfmt = 0; /* Use old libc5 format? */
char **show = NULL; /* What do they want us to show */
char *ufile; /* Filename of this file */
time_t lastdate; /* Last date we've seen */
char *progname; /* Name of this program */
#if CHOP_DOMAIN
char hostname[256]; /* For gethostbyname() */
char *domainname; /* Our domainname. */
#endif
/*
* Convert old utmp format to new.
*/
void uconv(struct oldutmp *oldut, struct utmp *utn)
{
memset(utn, 0, sizeof(struct utmp));
utn->ut_type = oldut->ut_type;
utn->ut_pid = oldut->ut_pid;
utn->ut_time = oldut->ut_oldtime;
utn->ut_addr = oldut->ut_oldaddr;
strncpy(utn->ut_line, oldut->ut_line, OLD_LINESIZE);
strncpy(utn->ut_user, oldut->ut_user, OLD_NAMESIZE);
strncpy(utn->ut_host, oldut->ut_host, OLD_HOSTSIZE);
}
#if NEW_UTMP
/*
* Read one utmp entry, return in new format.
* Automatically reposition file pointer.
*/
int uread(FILE *fp, struct utmp *u, int *quit)
{
static int utsize;
static char buf[UCHUNKSIZE];
char tmp[1024];
static off_t fpos;
static int bpos;
struct oldutmp uto;
int r;
off_t o;
if (quit == NULL && u != NULL) {
/*
* Normal read.
*/
if (oldfmt) {
r = fread(&uto, sizeof(uto), 1, fp);
uconv(&uto, u);
} else
r = fread(u, sizeof(struct utmp), 1, fp);
return r;
}
if (u == NULL) {
/*
* Initialize and position.
*/
utsize = oldfmt ? sizeof(uto) : sizeof(struct utmp);
fseeko(fp, 0, SEEK_END);
fpos = ftello(fp);
if (fpos == 0)
return 0;
o = ((fpos - 1) / UCHUNKSIZE) * UCHUNKSIZE;
if (fseeko(fp, o, SEEK_SET) < 0) {
fprintf(stderr, "%s: seek failed!\n", progname);
return 0;
}
bpos = (int)(fpos - o);
if (fread(buf, bpos, 1, fp) != 1) {
fprintf(stderr, "%s: read failed!\n", progname);
return 0;
}
fpos = o;
return 1;
}
/*
* Read one struct. From the buffer if possible.
*/
bpos -= utsize;
if (bpos >= 0) {
if (oldfmt)
uconv((struct oldutmp *)(buf + bpos), u);
else
memcpy(u, buf + bpos, sizeof(struct utmp));
return 1;
}
/*
* Oops we went "below" the buffer. We should be able to
* seek back UCHUNKSIZE bytes.
*/
fpos -= UCHUNKSIZE;
if (fpos < 0)
return 0;
/*
* Copy whatever is left in the buffer.
*/
memcpy(tmp + (-bpos), buf, utsize + bpos);
if (fseeko(fp, fpos, SEEK_SET) < 0) {
perror("fseek");
return 0;
}
/*
* Read another UCHUNKSIZE bytes.
*/
if (fread(buf, UCHUNKSIZE, 1, fp) != 1) {
perror("fread");
return 0;
}
/*
* The end of the UCHUNKSIZE byte buffer should be the first
* few bytes of the current struct utmp.
*/
memcpy(tmp, buf + UCHUNKSIZE + bpos, -bpos);
bpos += UCHUNKSIZE;
if (oldfmt)
uconv((struct oldutmp *)tmp, u);
else
memcpy(u, tmp, sizeof(struct utmp));
return 1;
}
#else /* NEW_UTMP */
/*
* Read one utmp entry, return in new format.
* Automatically reposition file pointer.
*/
int uread(FILE *fp, struct utmp *u, int *quit)
{
struct oldutmp uto;
off_t r;
if (u == NULL) {
r = oldfmt ? sizeof(struct oldutmp) : sizeof(struct utmp);
fseek(fp, -1 * r, SEEK_END);
return 1;
}
if (!oldfmt) {
r = fread(u, sizeof(struct utmp), 1, fp);
if (r == 1) {
if (fseeko(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)
if (quit) *quit = 1;
}
return r;
}
r = fread(&uto, sizeof(struct oldutmp), 1, fp);
if (r == 1) {
if (fseeko(fp, -2 * sizeof(struct oldutmp), SEEK_CUR) < 0)
if (quit) *quit = 1;
uconv(&uto, u);
}
return r;
}
#endif
/*
* Try to be smart about the location of the BTMP file
*/
#ifndef BTMP_FILE
#define BTMP_FILE getbtmp()
char *getbtmp()
{
static char btmp[128];
char *p;
strcpy(btmp, WTMP_FILE);
if ((p = strrchr(btmp, '/')) == NULL)
p = btmp;
else
p++;
*p = 0;
strcat(btmp, "btmp");
return btmp;
}
#endif
/*
* Print a short date.
*/
char *showdate()
{
char *s = ctime(&lastdate);
s[16] = 0;
return s;
}
/*
* SIGINT handler
*/
void int_handler()
{
printf("Interrupted %s\n", showdate());
exit(1);
}
/*
* SIGQUIT handler
*/
void quit_handler()
{
printf("Interrupted %s\n", showdate());
signal(SIGQUIT, quit_handler);
}
/*
* Get the basename of a filename
*/
char *mybasename(char *s)
{
char *p;
if ((p = strrchr(s, '/')) != NULL)
p++;
else
p = s;
return p;
}
/*
* Lookup a host with DNS.
*/
int dns_lookup(char *result, int size, int useip, int32_t *a)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr *sa;
int salen, flags;
unsigned int topnibble;
unsigned int azero = 0, sitelocal = 0;
int mapped = 0;
flags = useip ? NI_NUMERICHOST : 0;
/*
* IPv4 or IPv6 ? We use 2 heuristics:
* 1. Current IPv6 range uses 2000-3fff or fec0-feff.
* Outside of that is illegal and must be IPv4.
* 2. If last 3 bytes are 0, must be IPv4
* 3. If IPv6 in IPv4, handle as IPv4
*
* Ugly.
*/
if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))
mapped = 1;
topnibble = ntohl((unsigned int)a[0]) >> 28;
azero = ntohl((unsigned int)a[0]) >> 16;
sitelocal = (azero >= 0xfec0 && azero <= 0xfeff) ? 1 : 0;
if (((topnibble < 2 || topnibble > 3) && (!sitelocal)) || mapped ||
(a[1] == 0 && a[2] == 0 && a[3] == 0)) {
/* IPv4 */
sin.sin_family = AF_INET;
sin.sin_port = 0;
sin.sin_addr.s_addr = mapped ? a[3] : a[0];
sa = (struct sockaddr *)&sin;
salen = sizeof(sin);
} else {
/* IPv6 */
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = 0;
memcpy(sin6.sin6_addr.s6_addr, a, 16);
sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6);
}
return getnameinfo(sa, salen, result, size, NULL, 0, flags);
}
/*
* Show one line of information on screen
*/
int list(struct utmp *p, time_t t, int what)
{
time_t secs, tmp;
char logintime[32];
char logouttime[32];
char length[32];
char final[128];
char utline[UT_LINESIZE+1];
char domain[256];
char *s, **walk;
int mins, hours, days;
int r, len;
/*
* uucp and ftp have special-type entries
*/
utline[0] = 0;
strncat(utline, p->ut_line, UT_LINESIZE);
if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
utline[3] = 0;
if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
utline[4] = 0;
/*
* Is this something we wanna show?
*/
if (show) {
for (walk = show; *walk; walk++) {
if (strncmp(p->ut_name, *walk, UT_NAMESIZE) == 0 ||
strcmp(utline, *walk) == 0 ||
(strncmp(utline, "tty", 3) == 0 &&
strcmp(utline + 3, *walk) == 0)) break;
}
if (*walk == NULL) return 0;
}
/*
* Calculate times
*/
tmp = (time_t)p->ut_time;
strcpy(logintime, ctime(&tmp));
if (fulltime)
sprintf(logouttime, "- %s", ctime(&t));
else {
logintime[16] = 0;
sprintf(logouttime, "- %s", ctime(&t) + 11);
logouttime[7] = 0;
}
secs = t - p->ut_time;
mins = (secs / 60) % 60;
hours = (secs / 3600) % 24;
days = secs / 86400;
if (days)
sprintf(length, "(%d+%02d:%02d)", days, hours, mins);
else
sprintf(length, " (%02d:%02d)", hours, mins);
switch(what) {
case R_CRASH:
sprintf(logouttime, "- crash");
break;
case R_DOWN:
sprintf(logouttime, "- down ");
break;
case R_NOW:
length[0] = 0;
if (fulltime)
sprintf(logouttime, " still logged in");
else {
sprintf(logouttime, " still");
sprintf(length, "logged in");
}
break;
case R_PHANTOM:
length[0] = 0;
if (fulltime)
sprintf(logouttime, " gone - no logout");
else {
sprintf(logouttime, " gone");
sprintf(length, "- no logout");
}
break;
case R_REBOOT:
break;
case R_TIMECHANGE:
logouttime[0] = 0;
length[0] = 0;
break;
case R_NORMAL:
break;
}
/*
* Look up host with DNS if needed.
*/
r = -1;
if (usedns || useip)
r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);
if (r < 0) {
len = UT_HOSTSIZE;
if (len >= sizeof(domain)) len = sizeof(domain) - 1;
domain[0] = 0;
strncat(domain, p->ut_host, len);
}
if (showhost) {
#if CHOP_DOMAIN
/*
* See if this is in our domain.
*/
if (!usedns && (s = strchr(p->ut_host, '.')) != NULL &&
strcmp(s + 1, domainname) == 0) *s = 0;
#endif
if (!altlist) {
snprintf(final, sizeof(final),
fulltime ?
"%-8.8s %-12.12s %-16.16s %-24.24s %-26.26s %-12.12s\n" :
"%-8.8s %-12.12s %-16.16s %-16.16s %-7.7s %-12.12s\n",
p->ut_name, utline,
domain, logintime, logouttime, length);
} else {
snprintf(final, sizeof(final),
fulltime ?
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s %s\n",
p->ut_name, utline,
logintime, logouttime, length, domain);
}
} else
snprintf(final, sizeof(final),
fulltime ?
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
p->ut_name, utline,
logintime, logouttime, length);
/*
* Print out "final" string safely.
*/
for (s = final; *s; s++) {
if (*s == '\n' || (*s >= 32 && (unsigned char)*s <= 126))
putchar(*s);
else
putchar('*');
}
recsdone++;
if (maxrecs && recsdone >= maxrecs)
return 1;
return 0;
}
/*
* show usage
*/
void usage(char *s)
{
fprintf(stderr, "Usage: %s [-num | -n num] [-f file] "
"[-t YYYYMMDDHHMMSS] "
"[-R] [-adioxF] [username..] [tty..]\n", s);
exit(1);
}
time_t parsetm(char *ts)
{
struct tm u, origu;
time_t tm;
memset(&tm, 0, sizeof(tm));
if (sscanf(ts, "%4d%2d%2d%2d%2d%2d", &u.tm_year,
&u.tm_mon, &u.tm_mday, &u.tm_hour, &u.tm_min,
&u.tm_sec) != 6)
return (time_t)-1;
u.tm_year -= 1900;
u.tm_mon -= 1;
u.tm_isdst = -1;
origu = u;
if ((tm = mktime(&u)) == (time_t)-1)
return tm;
/*
* Unfortunately mktime() is much more forgiving than
* it should be. For example, it'll gladly accept
* "30" as a valid month number. This behavior is by
* design, but we don't like it, so we want to detect
* it and complain.
*/
if (u.tm_year != origu.tm_year ||
u.tm_mon != origu.tm_mon ||
u.tm_mday != origu.tm_mday ||
u.tm_hour != origu.tm_hour ||
u.tm_min != origu.tm_min ||
u.tm_sec != origu.tm_sec)
return (time_t)-1;
return tm;
}
int main(int argc, char **argv)
{
FILE *fp; /* Filepointer of wtmp file */
struct utmp ut; /* Current utmp entry */
struct utmp oldut; /* Old utmp entry to check for duplicates */
struct utmplist *p; /* Pointer into utmplist */
struct utmplist *next;/* Pointer into utmplist */
time_t lastboot = 0; /* Last boottime */
time_t lastrch = 0; /* Last run level change */
time_t lastdown; /* Last downtime */
time_t begintime; /* When wtmp begins */
int whydown = 0; /* Why we went down: crash or shutdown */
int c, x; /* Scratch */
struct stat st; /* To stat the [uw]tmp file */
int quit = 0; /* Flag */
int down = 0; /* Down flag */
int lastb = 0; /* Is this 'lastb' ? */
int extended = 0; /* Lots of info. */
char *altufile = NULL;/* Alternate wtmp */
time_t until = 0; /* at what time to stop parsing the file */
progname = mybasename(argv[0]);
/* Process the arguments. */
while((c = getopt(argc, argv, "f:n:RxadFiot:0123456789")) != EOF)
switch(c) {
case 'R':
showhost = 0;
break;
case 'x':
extended = 1;
break;
case 'n':
maxrecs = atoi(optarg);
break;
case 'o':
oldfmt = 1;
break;
case 'f':
if((altufile = malloc(strlen(optarg)+1)) == NULL) {
fprintf(stderr, "%s: out of memory\n",
progname);
exit(1);
}
strcpy(altufile, optarg);
break;
case 'd':
usedns++;
break;
case 'i':
useip++;
break;
case 'a':
altlist++;
break;
case 'F':
fulltime++;
break;
case 't':
if ((until = parsetm(optarg)) == (time_t)-1) {
fprintf(stderr, "%s: Invalid time value \"%s\"\n",
progname, optarg);
usage(progname);
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
maxrecs = 10*maxrecs + c - '0';
break;
default:
usage(progname);
break;
}
if (optind < argc) show = argv + optind;
/*
* Which file do we want to read?
*/
if (strcmp(progname, "lastb") == 0) {
ufile = BTMP_FILE;
lastb = 1;
} else
ufile = WTMP_FILE;
if (altufile)
ufile = altufile;
time(&lastdown);
lastrch = lastdown;
/*
* Fill in 'lastdate'
*/
lastdate = lastdown;
#if CHOP_DOMAIN
/*
* Find out domainname.
*
* This doesn't work on modern systems, where only a DNS
* lookup of the result from hostname() will get you the domainname.
* Remember that domainname() is the NIS domainname, not DNS.
* So basically this whole piece of code is bullshit.
*/
hostname[0] = 0;
(void) gethostname(hostname, sizeof(hostname));
if ((domainname = strchr(hostname, '.')) != NULL) domainname++;
if (domainname == NULL || domainname[0] == 0) {
hostname[0] = 0;
(void) getdomainname(hostname, sizeof(hostname));
hostname[sizeof(hostname) - 1] = 0;
domainname = hostname;
if (strcmp(domainname, "(none)") == 0 || domainname[0] == 0)
domainname = NULL;
}
#endif
/*
* Install signal handlers
*/
signal(SIGINT, int_handler);
signal(SIGQUIT, quit_handler);
/*
* Open the utmp file
*/
if ((fp = fopen(ufile, "r")) == NULL) {
x = errno;
fprintf(stderr, "%s: %s: %s\n", progname, ufile, strerror(errno));
if (altufile == NULL && x == ENOENT)
fprintf(stderr, "Perhaps this file was removed by the "
"operator to prevent logging %s info.\n", progname);
exit(1);
}
/*
* Optimize the buffer size.
*/
setvbuf(fp, NULL, _IOFBF, UCHUNKSIZE);
/*
* Read first structure to capture the time field
*/
if (uread(fp, &ut, NULL) == 1)
begintime = ut.ut_time;
else {
fstat(fileno(fp), &st);
begintime = st.st_ctime;
quit = 1;
}
/*
* Go to end of file minus one structure
* and/or initialize utmp reading code.
*/
uread(fp, NULL, NULL);
/*
* Read struct after struct backwards from the file.
*/
while(!quit) {
if (uread(fp, &ut, &quit) != 1)
break;
if (until && until < ut.ut_time)
continue;
if (memcmp(&ut, &oldut, sizeof(struct utmp)) == 0) continue;
memcpy(&oldut, &ut, sizeof(struct utmp));
lastdate = ut.ut_time;
if (lastb) {
quit = list(&ut, ut.ut_time, R_NORMAL);
continue;
}
/*
* Set ut_type to the correct type.
*/
if (strncmp(ut.ut_line, "~", 1) == 0) {
if (strncmp(ut.ut_user, "shutdown", 8) == 0)
ut.ut_type = SHUTDOWN_TIME;
else if (strncmp(ut.ut_user, "reboot", 6) == 0)
ut.ut_type = BOOT_TIME;
else if (strncmp(ut.ut_user, "runlevel", 8) == 0)
ut.ut_type = RUN_LVL;
}
#if 1 /*def COMPAT*/
/*
* For stupid old applications that don't fill in
* ut_type correctly.
*/
else {
if (ut.ut_type != DEAD_PROCESS &&
ut.ut_name[0] && ut.ut_line[0] &&
strcmp(ut.ut_name, "LOGIN") != 0)
ut.ut_type = USER_PROCESS;
/*
* Even worse, applications that write ghost
* entries: ut_type set to USER_PROCESS but
* empty ut_name...
*/
if (ut.ut_name[0] == 0)
ut.ut_type = DEAD_PROCESS;
/*
* Clock changes.
*/
if (strcmp(ut.ut_name, "date") == 0) {
if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
}
}
#endif
switch (ut.ut_type) {
case SHUTDOWN_TIME:
if (extended) {
strcpy(ut.ut_line, "system down");
quit = list(&ut, lastboot, R_NORMAL);
}
lastdown = lastrch = ut.ut_time;
down = 1;
break;
case OLD_TIME:
case NEW_TIME:
if (extended) {
strcpy(ut.ut_line,
ut.ut_type == NEW_TIME ? "new time" :
"old time");
quit = list(&ut, lastdown, R_TIMECHANGE);
}
break;
case BOOT_TIME:
strcpy(ut.ut_line, "system boot");
quit = list(&ut, lastdown, R_REBOOT);
lastboot = ut.ut_time;
down = 1;
break;
case RUN_LVL:
x = ut.ut_pid & 255;
if (extended) {
sprintf(ut.ut_line, "(to lvl %c)", x);
quit = list(&ut, lastrch, R_NORMAL);
}
if (x == '0' || x == '6') {
lastdown = ut.ut_time;
down = 1;
ut.ut_type = SHUTDOWN_TIME;
}
lastrch = ut.ut_time;
break;
case USER_PROCESS:
/*
* This was a login - show the first matching
* logout record and delete all records with
* the same ut_line.
*/
c = 0;
for (p = utmplist; p; p = next) {
next = p->next;
if (strncmp(p->ut.ut_line, ut.ut_line,
UT_LINESIZE) == 0) {
/* Show it */
if (c == 0) {
quit = list(&ut, p->ut.ut_time,
R_NORMAL);
c = 1;
}
if (p->next) p->next->prev = p->prev;
if (p->prev)
p->prev->next = p->next;
else
utmplist = p->next;
free(p);
}
}
/*
* Not found? Then crashed, down, still
* logged in, or missing logout record.
*/
if (c == 0) {
if (lastboot == 0) {
c = R_NOW;
/* Is process still alive? */
if (ut.ut_pid > 0 &&
kill(ut.ut_pid, 0) != 0 &&
errno == ESRCH)
c = R_PHANTOM;
} else
c = whydown;
quit = list(&ut, lastboot, c);
}
/* FALLTHRU */
case DEAD_PROCESS:
/*
* Just store the data if it is
* interesting enough.
*/
if (ut.ut_line[0] == 0)
break;
if ((p = malloc(sizeof(struct utmplist))) == NULL) {
fprintf(stderr, "%s: out of memory\n",
progname);
exit(1);
}
memcpy(&p->ut, &ut, sizeof(struct utmp));
p->next = utmplist;
p->prev = NULL;
if (utmplist) utmplist->prev = p;
utmplist = p;
break;
}
/*
* If we saw a shutdown/reboot record we can remove
* the entire current utmplist.
*/
if (down) {
lastboot = ut.ut_time;
whydown = (ut.ut_type == SHUTDOWN_TIME) ? R_DOWN : R_CRASH;
for (p = utmplist; p; p = next) {
next = p->next;
free(p);
}
utmplist = NULL;
down = 0;
}
}
printf("\n%s begins %s", mybasename(ufile), ctime(&begintime));
fclose(fp);
/*
* Should we free memory here? Nah. This is not NT :)
*/
return 0;
}

124
src/mesg.c Normal file
View File

@ -0,0 +1,124 @@
/*
* mesg.c The "mesg" utility. Gives / restrict access to
* your terminal by others.
*
* Usage: mesg [y|n].
* Without arguments prints out the current settings.
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2001 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <grp.h>
char *Version = "@(#) mesg 2.81 31-Jul-2001 miquels@cistron.nl";
#define TTYGRP "tty"
/*
* See if the system has a special 'tty' group.
* If it does, and the tty device is in that group,
* we set the modes to -rw--w--- instead if -rw--w--w.
*/
int hasttygrp(void)
{
struct group *grp;
if ((grp = getgrnam(TTYGRP)) != NULL)
return 1;
return 0;
}
/*
* See if the tty devices group is indeed 'tty'
*/
int tty_in_ttygrp(struct stat *st)
{
struct group *gr;
if ((gr = getgrgid(st->st_gid)) == NULL)
return 0;
if (strcmp(gr->gr_name, TTYGRP) != 0)
return 0;
return 1;
}
int main(int argc, char **argv)
{
struct stat st;
unsigned int ttymode, st_mode_old;
int ht;
int it;
int e;
if (!isatty(0)) {
/* Or should we look in /var/run/utmp? */
fprintf(stderr, "stdin: is not a tty\n");
return(1);
}
if (fstat(0, &st) < 0) {
perror("fstat");
return(1);
}
ht = hasttygrp();
it = tty_in_ttygrp(&st);
if (argc < 2) {
ttymode = (ht && it) ? 020 : 002;
printf("is %s\n", (st.st_mode & ttymode) ? "y" : "n");
return 0;
}
if (argc > 2 || (argv[1][0] != 'y' && argv[1][0] != 'n')) {
fprintf(stderr, "Usage: mesg [y|n]\n");
return 1;
}
/*
* Security check: allow mesg n when group is
* weird, but don't allow mesg y.
*/
ttymode = ht ? 020 : 022;
if (ht && !it && argv[1][0] == 'y') {
fprintf(stderr, "mesg: error: tty device is not owned "
"by group `%s'\n", TTYGRP);
exit(1);
}
st_mode_old = st.st_mode;
if (argv[1][0] == 'y')
st.st_mode |= ttymode;
else
st.st_mode &= ~(ttymode);
if (st_mode_old != st.st_mode && fchmod(0, st.st_mode) != 0) {
e = errno;
fprintf(stderr, "mesg: %s: %s\n",
ttyname(0), strerror(e));
exit(1);
}
return 0;
}

128
src/mountpoint.c Normal file
View File

@ -0,0 +1,128 @@
/*
* mountpoint See if a directory is a mountpoint.
*
* Author: Miquel van Smoorenburg.
*
* Version: @(#)mountpoint 2.85-12 17-Mar-2004 miquels@cistron.nl
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <getopt.h>
#include <stdio.h>
int dostat(char *path, struct stat *st, int do_lstat, int quiet)
{
int n;
if (do_lstat)
n = lstat(path, st);
else
n = stat(path, st);
if (n != 0) {
if (!quiet)
fprintf(stderr, "mountpoint: %s: %s\n", path,
strerror(errno));
return -1;
}
return 0;
}
void usage(void) {
fprintf(stderr, "Usage: mountpoint [-q] [-d] [-x] path\n");
exit(1);
}
int main(int argc, char **argv)
{
struct stat st, st2;
char buf[256];
char *path;
int quiet = 0;
int showdev = 0;
int xdev = 0;
int c, r;
while ((c = getopt(argc, argv, "dqx")) != EOF) switch(c) {
case 'd':
showdev = 1;
break;
case 'q':
quiet = 1;
break;
case 'x':
xdev = 1;
break;
default:
usage();
break;
}
if (optind != argc - 1) usage();
path = argv[optind];
if (dostat(path, &st, !xdev, quiet) < 0)
return 1;
if (xdev) {
#ifdef __linux__
if (!S_ISBLK(st.st_mode))
#else
if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
#endif
{
if (quiet)
printf("\n");
else
fprintf(stderr, "mountpoint: %s: not a block device\n",
path);
return 1;
}
printf("%u:%u\n", major(st.st_rdev), minor(st.st_rdev));
return 0;
}
if (!S_ISDIR(st.st_mode)) {
if (!quiet)
fprintf(stderr, "mountpoint: %s: not a directory\n",
path);
return 1;
}
memset(buf, 0, sizeof(buf));
strncpy(buf, path, sizeof(buf) - 4);
strcat(buf, "/..");
if (dostat(buf, &st2, 0, quiet) < 0)
return 1;
r = (st.st_dev != st2.st_dev) ||
(st.st_dev == st2.st_dev && st.st_ino == st2.st_ino);
if (!quiet && !showdev)
printf("%s is %sa mountpoint\n", path, r ? "" : "not ");
if (showdev)
printf("%u:%u\n", major(st.st_dev), minor(st.st_dev));
return r ? 0 : 1;
}

41
src/oldutmp.h Normal file
View File

@ -0,0 +1,41 @@
/*
* oldutmp.h Definition of the old libc5 utmp structure.
*
* Version: @(#)oldutmp.h 1.00 29-Mar-1998 miquels@cistron.nl
*
* Copyright (C) 1991-2000 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef OLD_UTMP_H
#define OLD_UTMP_H
#define OLD_LINESIZE 12
#define OLD_NAMESIZE 8
#define OLD_HOSTSIZE 16
struct oldutmp {
short ut_type;
int ut_pid;
char ut_line[OLD_LINESIZE];
char ut_id[4];
long ut_oldtime;
char ut_user[OLD_NAMESIZE];
char ut_host[OLD_HOSTSIZE];
long ut_oldaddr;
};
#endif

49
src/paths.h Normal file
View File

@ -0,0 +1,49 @@
/*
* paths.h Paths of files that init and related utilities need.
*
* Version: @(#) paths.h 2.85-8 05-Nov-2003
*
* Author: Miquel van Smoorenburg, <miquels@cistron.nl>
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2001 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define VT_MASTER "/dev/tty0" /* Virtual console master */
#define CONSOLE "/dev/console" /* Logical system console */
#define SECURETTY "/etc/securetty" /* List of root terminals */
#define SDALLOW "/etc/shutdown.allow" /* Users allowed to shutdown */
#define INITTAB "/etc/inittab" /* Location of inittab */
#define INIT "/sbin/init" /* Location of init itself. */
#define NOLOGIN "/etc/nologin" /* Stop user logging in. */
#define FASTBOOT "/fastboot" /* Enable fast boot. */
#define FORCEFSCK "/forcefsck" /* Force fsck on boot */
#define SDPID "/var/run/shutdown.pid" /* PID of shutdown program */
#define SHELL "/bin/sh" /* Default shell */
#define SULOGIN "/sbin/sulogin" /* Sulogin */
#define INITSCRIPT "/etc/initscript" /* Initscript. */
#define PWRSTAT "/etc/powerstatus" /* COMPAT: SIGPWR reason (OK/BAD) */
#if 0
#define INITLVL "/etc/initrunlvl" /* COMPAT: New runlevel */
#define INITLVL2 "/var/log/initrunlvl" /* COMPAT: New runlevel */
/* Note: INITLVL2 definition needs INITLVL */
#define HALTSCRIPT1 "/etc/init.d/halt" /* Called by "fast" shutdown */
#define HALTSCRIPT2 "/etc/rc.d/rc.0" /* Called by "fast" shutdown */
#define REBOOTSCRIPT1 "/etc/init.d/reboot" /* Ditto. */
#define REBOOTSCRIPT2 "/etc/rc.d/rc.6" /* Ditto. */
#endif

51
src/reboot.h Normal file
View File

@ -0,0 +1,51 @@
/*
* reboot.h Headerfile that defines how to handle
* the reboot() system call.
*
* Version: @(#)reboot.h 2.85-17 04-Jun-2004 miquels@cistron.nl
*
* Copyright (C) (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/reboot.h>
#ifdef RB_ENABLE_CAD
# define BMAGIC_HARD RB_ENABLE_CAD
#endif
#ifdef RB_DISABLE_CAD
# define BMAGIC_SOFT RB_DISABLE_CAD
#endif
#ifdef RB_HALT_SYSTEM
# define BMAGIC_HALT RB_HALT_SYSTEM
#else
# define BMAGIC_HALT RB_HALT
#endif
#define BMAGIC_REBOOT RB_AUTOBOOT
#ifdef RB_POWER_OFF
# define BMAGIC_POWEROFF RB_POWER_OFF
#elif defined(RB_POWEROFF)
# define BMAGIC_POWEROFF RB_POWEROFF
#else
# define BMAGIC_POWEROFF BMAGIC_HALT
#endif
#define init_reboot(magic) reboot(magic)

53
src/runlevel.c Normal file
View File

@ -0,0 +1,53 @@
/*
* runlevel Prints out the previous and the current runlevel.
*
* Version: @(#)runlevel 1.20 16-Apr-1997 MvS
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-1997 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <utmp.h>
#include <time.h>
#include <stdlib.h>
int main(argc, argv)
int argc;
char **argv;
{
struct utmp *ut;
char prev;
if (argc > 1) utmpname(argv[1]);
setutent();
while ((ut = getutent()) != NULL) {
if (ut->ut_type == RUN_LVL) {
prev = ut->ut_pid / 256;
if (prev == 0) prev = 'N';
printf("%c %c\n", prev, ut->ut_pid % 256);
endutent();
exit(0);
}
}
printf("unknown\n");
endutent();
return(1);
}

28
src/set.h Normal file
View File

@ -0,0 +1,28 @@
/*
* set.h Macros that look like sigaddset et al. but
* aren't. They are used to manipulate bits in
* an integer, to do our signal bookeeping.
*
* Copyright (C) 2005 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#define ISMEMBER(set, val) ((set) & (1 << (val)))
#define DELSET(set, val) ((set) &= ~(1 << (val)))
#define ADDSET(set, val) ((set) |= (1 << (val)))
#define EMPTYSET(set) ((set) = 0)

727
src/shutdown.c Normal file
View File

@ -0,0 +1,727 @@
/*
* shutdown.c Shut the system down.
*
* Usage: shutdown [-krhfnc] time [warning message]
* -k: don't really shutdown, only warn.
* -r: reboot after shutdown.
* -h: halt after shutdown.
* -f: do a 'fast' reboot (skip fsck).
* -F: Force fsck on reboot.
* -n: do not go through init but do it ourselves.
* -c: cancel an already running shutdown.
* -t secs: delay between SIGTERM and SIGKILL for init.
*
* Author: Miquel van Smoorenburg, miquels@cistron.nl
*
* Version: @(#)shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <utmp.h>
#include <syslog.h>
#include "paths.h"
#include "reboot.h"
#include "initreq.h"
char *Version = "@(#) shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl";
#define MESSAGELEN 256
int dontshut = 0; /* Don't shutdown, only warn */
char down_level[2]; /* What runlevel to go to. */
int dosync = 1; /* Sync before reboot or halt */
int fastboot = 0; /* Do a 'fast' reboot */
int forcefsck = 0; /* Force fsck on reboot */
char message[MESSAGELEN]; /* Warning message */
char *sltime = 0; /* Sleep time */
char newstate[64]; /* What are we gonna do */
int doself = 0; /* Don't use init */
int got_alrm = 0;
char *clean_env[] = {
"HOME=/",
"PATH=/bin:/usr/bin:/sbin:/usr/sbin",
"TERM=dumb",
NULL,
};
/* From "wall.c" */
extern void wall(char *, int, int);
/* From "utmp.c" */
extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
/*
* Sleep without being interrupted.
*/
void hardsleep(int secs)
{
struct timespec ts, rem;
ts.tv_sec = secs;
ts.tv_nsec = 0;
while(nanosleep(&ts, &rem) < 0 && errno == EINTR)
ts = rem;
}
/*
* Break off an already running shutdown.
*/
void stopit(int sig)
{
unlink(NOLOGIN);
unlink(FASTBOOT);
unlink(FORCEFSCK);
unlink(SDPID);
printf("\r\nShutdown cancelled.\r\n");
exit(0);
}
/*
* Show usage message.
*/
void usage(void)
{
fprintf(stderr,
"Usage:\t shutdown [-akrhHPfnc] [-t secs] time [warning message]\n"
"\t\t -a: use /etc/shutdown.allow\n"
"\t\t -k: don't really shutdown, only warn.\n"
"\t\t -r: reboot after shutdown.\n"
"\t\t -h: halt after shutdown.\n"
"\t\t -P: halt action is to turn off power.\n"
"\t\t -H: halt action is to just halt.\n"
"\t\t -f: do a 'fast' reboot (skip fsck).\n"
"\t\t -F: Force fsck on reboot.\n"
"\t\t -n: do not go through \"init\" but go down real fast.\n"
"\t\t -c: cancel a running shutdown.\n"
"\t\t -t secs: delay between warning and kill signal.\n"
"\t\t ** the \"time\" argument is mandatory! (try \"now\") **\n");
exit(1);
}
void alrm_handler(int sig)
{
got_alrm = sig;
}
/*
* Set environment variables in the init process.
*/
int init_setenv(char *name, char *value)
{
struct init_request request;
struct sigaction sa;
int fd;
int nl, vl;
memset(&request, 0, sizeof(request));
request.magic = INIT_MAGIC;
request.cmd = INIT_CMD_SETENV;
nl = strlen(name);
vl = value ? strlen(value) : 0;
if (nl + vl + 3 >= sizeof(request.i.data))
return -1;
memcpy(request.i.data, name, nl);
if (value) {
request.i.data[nl] = '=';
memcpy(request.i.data + nl + 1, value, vl);
}
/*
* Open the fifo and write the command.
* Make sure we don't hang on opening /dev/initctl
*/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = alrm_handler;
sigaction(SIGALRM, &sa, NULL);
got_alrm = 0;
alarm(3);
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0 &&
write(fd, &request, sizeof(request)) == sizeof(request)) {
close(fd);
alarm(0);
return 0;
}
fprintf(stderr, "shutdown: ");
if (got_alrm) {
fprintf(stderr, "timeout opening/writing control channel %s\n",
INIT_FIFO);
} else {
perror(INIT_FIFO);
}
return -1;
}
/*
* Tell everyone the system is going down in 'mins' minutes.
*/
void warn(int mins)
{
char buf[MESSAGELEN + sizeof(newstate)];
int len;
buf[0] = 0;
strncat(buf, message, sizeof(buf) - 1);
len = strlen(buf);
if (mins == 0)
snprintf(buf + len, sizeof(buf) - len,
"\rThe system is going down %s NOW!\r\n",
newstate);
else
snprintf(buf + len, sizeof(buf) - len,
"\rThe system is going DOWN %s in %d minute%s!\r\n",
newstate, mins, mins == 1 ? "" : "s");
wall(buf, 1, 0);
}
/*
* Create the /etc/nologin file.
*/
void donologin(int min)
{
FILE *fp;
time_t t;
time(&t);
t += 60 * min;
if ((fp = fopen(NOLOGIN, "w")) != NULL) {
fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
if (message[0]) fputs(message, fp);
fclose(fp);
}
}
/*
* Spawn an external program.
*/
int spawn(int noerr, char *prog, ...)
{
va_list ap;
pid_t pid, rc;
int i;
char *argv[8];
i = 0;
while ((pid = fork()) < 0 && i < 10) {
perror("fork");
sleep(5);
i++;
}
if (pid < 0) return -1;
if (pid > 0) {
while((rc = wait(&i)) != pid)
if (rc < 0 && errno == ECHILD)
break;
return (rc == pid) ? WEXITSTATUS(i) : -1;
}
if (noerr) fclose(stderr);
argv[0] = prog;
va_start(ap, prog);
for (i = 1; i < 7 && (argv[i] = va_arg(ap, char *)) != NULL; i++)
;
argv[i] = NULL;
va_end(ap);
chdir("/");
environ = clean_env;
execvp(argv[0], argv);
perror(argv[0]);
exit(1);
/*NOTREACHED*/
return 0;
}
/*
* Kill all processes, call /etc/init.d/halt (if present)
*/
void fastdown()
{
int do_halt = (down_level[0] == '0');
int i;
#if 0
char cmd[128];
char *script;
/*
* Currently, the halt script is either init.d/halt OR rc.d/rc.0,
* likewise for the reboot script. Test for the presence
* of either.
*/
if (do_halt) {
if (access(HALTSCRIPT1, X_OK) == 0)
script = HALTSCRIPT1;
else
script = HALTSCRIPT2;
} else {
if (access(REBOOTSCRIPT1, X_OK) == 0)
script = REBOOTSCRIPT1;
else
script = REBOOTSCRIPT2;
}
#endif
/* First close all files. */
for(i = 0; i < 3; i++)
if (!isatty(i)) {
close(i);
open("/dev/null", O_RDWR);
}
for(i = 3; i < 20; i++) close(i);
close(255);
/* First idle init. */
if (kill(1, SIGTSTP) < 0) {
fprintf(stderr, "shutdown: can't idle init.\r\n");
exit(1);
}
/* Kill all processes. */
fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
kill(-1, SIGTERM);
sleep(sltime ? atoi(sltime) : 3);
fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
(void) kill(-1, SIGKILL);
#if 0
/* See if we can run /etc/init.d/halt */
if (access(script, X_OK) == 0) {
spawn(1, cmd, "fast", NULL);
fprintf(stderr, "shutdown: %s returned - falling back "
"on default routines\r\n", script);
}
#endif
/* script failed or not present: do it ourself. */
sleep(1); /* Give init the chance to collect zombies. */
/* Record the fact that we're going down */
write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
/* This is for those who have quota installed. */
spawn(1, "accton", NULL);
spawn(1, "quotaoff", "-a", NULL);
sync();
fprintf(stderr, "shutdown: turning off swap\r\n");
spawn(0, "swapoff", "-a", NULL);
fprintf(stderr, "shutdown: unmounting all file systems\r\n");
spawn(0, "umount", "-a", NULL);
/* We're done, halt or reboot now. */
if (do_halt) {
fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL "
"or turn off power\r\n");
init_reboot(BMAGIC_HALT);
exit(0);
}
fprintf(stderr, "Please stand by while rebooting the system.\r\n");
init_reboot(BMAGIC_REBOOT);
exit(0);
}
/*
* Go to runlevel 0, 1 or 6.
*/
void shutdown(char *halttype)
{
char *args[8];
int argp = 0;
int do_halt = (down_level[0] == '0');
/* Warn for the last time */
warn(0);
if (dontshut) {
hardsleep(1);
stopit(0);
}
openlog("shutdown", LOG_PID, LOG_USER);
if (do_halt)
syslog(LOG_NOTICE, "shutting down for system halt");
else
syslog(LOG_NOTICE, "shutting down for system reboot");
closelog();
/* See if we have to do it ourself. */
if (doself) fastdown();
/* Create the arguments for init. */
args[argp++] = INIT;
if (sltime) {
args[argp++] = "-t";
args[argp++] = sltime;
}
args[argp++] = down_level;
args[argp] = (char *)NULL;
unlink(SDPID);
unlink(NOLOGIN);
/* Now execute init to change runlevel. */
sync();
init_setenv("INIT_HALT", halttype);
execv(INIT, args);
/* Oops - failed. */
fprintf(stderr, "\rshutdown: cannot execute %s\r\n", INIT);
unlink(FASTBOOT);
unlink(FORCEFSCK);
init_setenv("INIT_HALT", NULL);
openlog("shutdown", LOG_PID, LOG_USER);
syslog(LOG_NOTICE, "shutdown failed");
closelog();
exit(1);
}
/*
* returns if a warning is to be sent for wt
*/
static int needwarning(int wt)
{
int ret;
if (wt < 10)
ret = 1;
else if (wt < 60)
ret = (wt % 15 == 0);
else if (wt < 180)
ret = (wt % 30 == 0);
else
ret = (wt % 60 == 0);
return ret;
}
/*
* Main program.
* Process the options and do the final countdown.
*/
int main(int argc, char **argv)
{
FILE *fp;
extern int getopt();
extern int optind;
struct sigaction sa;
struct tm *lt;
struct stat st;
struct utmp *ut;
time_t t;
uid_t realuid;
char *halttype;
char *downusers[32];
char buf[128];
char term[UT_LINESIZE + 6];
char *sp;
char *when = NULL;
int c, i, wt;
int hours, mins;
int didnolog = 0;
int cancel = 0;
int useacl = 0;
int pid = 0;
int user_ok = 0;
/* We can be installed setuid root (executable for a special group) */
realuid = getuid();
setuid(geteuid());
if (getuid() != 0) {
fprintf(stderr, "shutdown: you must be root to do that!\n");
exit(1);
}
strcpy(down_level, "1");
halttype = NULL;
/* Process the options. */
while((c = getopt(argc, argv, "HPacqkrhnfFyt:g:i:")) != EOF) {
switch(c) {
case 'H':
halttype = "HALT";
break;
case 'P':
halttype = "POWERDOWN";
break;
case 'a': /* Access control. */
useacl = 1;
break;
case 'c': /* Cancel an already running shutdown. */
cancel = 1;
break;
case 'k': /* Don't really shutdown, only warn.*/
dontshut = 1;
break;
case 'r': /* Automatic reboot */
down_level[0] = '6';
break;
case 'h': /* Halt after shutdown */
down_level[0] = '0';
break;
case 'f': /* Don't perform fsck after next boot */
fastboot = 1;
break;
case 'F': /* Force fsck after next boot */
forcefsck = 1;
break;
case 'n': /* Don't switch runlevels. */
doself = 1;
break;
case 't': /* Delay between TERM and KILL */
sltime = optarg;
break;
case 'y': /* Ignored for sysV compatibility */
break;
case 'g': /* sysv style to specify time. */
when = optarg;
break;
case 'i': /* Level to go to. */
if (!strchr("0156aAbBcCsS", optarg[0])) {
fprintf(stderr,
"shutdown: `%s': bad runlevel\n",
optarg);
exit(1);
}
down_level[0] = optarg[0];
break;
default:
usage();
break;
}
}
if (NULL != halttype && down_level[0] != '0') {
fprintf(stderr, "shutdown: -H and -P flags can only be used along with -h flag.\n");
usage();
exit(1);
}
/* Do we need to use the shutdown.allow file ? */
if (useacl && (fp = fopen(SDALLOW, "r")) != NULL) {
/* Read /etc/shutdown.allow. */
i = 0;
while(fgets(buf, 128, fp)) {
if (buf[0] == '#' || buf[0] == '\n') continue;
if (i > 31) continue;
for(sp = buf; *sp; sp++) if (*sp == '\n') *sp = 0;
downusers[i++] = strdup(buf);
}
if (i < 32) downusers[i] = 0;
fclose(fp);
/* Now walk through /var/run/utmp to find logged in users. */
while(!user_ok && (ut = getutent()) != NULL) {
/* See if this is a user process on a VC. */
if (ut->ut_type != USER_PROCESS) continue;
sprintf(term, "/dev/%.*s", UT_LINESIZE, ut->ut_line);
if (stat(term, &st) < 0) continue;
#ifdef major /* glibc */
if (major(st.st_rdev) != 4 ||
minor(st.st_rdev) > 63) continue;
#else
if ((st.st_rdev & 0xFFC0) != 0x0400) continue;
#endif
/* Root is always OK. */
if (strcmp(ut->ut_user, "root") == 0) {
user_ok++;
break;
}
/* See if this is an allowed user. */
for(i = 0; i < 32 && downusers[i]; i++)
if (!strncmp(downusers[i], ut->ut_user,
UT_NAMESIZE)) {
user_ok++;
break;
}
}
endutent();
/* See if user was allowed. */
if (!user_ok) {
if ((fp = fopen(CONSOLE, "w")) != NULL) {
fprintf(fp, "\rshutdown: no authorized users "
"logged in.\r\n");
fclose(fp);
}
exit(1);
}
}
/* Read pid of running shutdown from a file */
if ((fp = fopen(SDPID, "r")) != NULL) {
fscanf(fp, "%d", &pid);
fclose(fp);
}
/* Read remaining words, skip time if needed. */
message[0] = 0;
for(c = optind + (!cancel && !when); c < argc; c++) {
if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN)
break;
strcat(message, argv[c]);
strcat(message, " ");
}
if (message[0]) strcat(message, "\r\n");
/* See if we want to run or cancel. */
if (cancel) {
if (pid <= 0) {
fprintf(stderr, "shutdown: cannot find pid "
"of running shutdown.\n");
exit(1);
}
init_setenv("INIT_HALT", NULL);
if (kill(pid, SIGINT) < 0) {
fprintf(stderr, "shutdown: not running.\n");
exit(1);
}
if (message[0]) wall(message, 1, 0);
exit(0);
}
/* Check syntax. */
if (when == NULL) {
if (optind == argc) usage();
when = argv[optind++];
}
/* See if we are already running. */
if (pid > 0 && kill(pid, 0) == 0) {
fprintf(stderr, "\rshutdown: already running.\r\n");
exit(1);
}
/* Extra check. */
if (doself && down_level[0] != '0' && down_level[0] != '6') {
fprintf(stderr,
"shutdown: can use \"-n\" for halt or reboot only.\r\n");
exit(1);
}
/* Tell users what we're gonna do. */
switch(down_level[0]) {
case '0':
strcpy(newstate, "for system halt");
break;
case '6':
strcpy(newstate, "for reboot");
break;
case '1':
strcpy(newstate, "to maintenance mode");
break;
default:
sprintf(newstate, "to runlevel %s", down_level);
break;
}
/* Create a new PID file. */
unlink(SDPID);
umask(022);
if ((fp = fopen(SDPID, "w")) != NULL) {
fprintf(fp, "%d\n", getpid());
fclose(fp);
} else if (errno != EROFS)
fprintf(stderr, "shutdown: warning: cannot open %s\n", SDPID);
/*
* Catch some common signals.
*/
signal(SIGQUIT, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = stopit;
sigaction(SIGINT, &sa, NULL);
/* Go to the root directory */
chdir("/");
if (fastboot) close(open(FASTBOOT, O_CREAT | O_RDWR, 0644));
if (forcefsck) close(open(FORCEFSCK, O_CREAT | O_RDWR, 0644));
/* Alias now and take care of old '+mins' notation. */
if (!strcmp(when, "now")) strcpy(when, "0");
if (when[0] == '+') when++;
/* Decode shutdown time. */
for (sp = when; *sp; sp++) {
if (*sp != ':' && (*sp < '0' || *sp > '9'))
usage();
}
if (strchr(when, ':') == NULL) {
/* Time in minutes. */
wt = atoi(when);
if (wt == 0 && when[0] != '0') usage();
} else {
/* Time in hh:mm format. */
if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
if (hours > 23 || mins > 59) usage();
time(&t);
lt = localtime(&t);
wt = (60*hours + mins) - (60*lt->tm_hour + lt->tm_min);
if (wt < 0) wt += 1440;
}
/* Shutdown NOW if time == 0 */
if (wt == 0) shutdown(halttype);
/* Give warnings on regular intervals and finally shutdown. */
if (wt < 15 && !needwarning(wt)) warn(wt);
while(wt) {
if (wt <= 5 && !didnolog) {
donologin(wt);
didnolog++;
}
if (needwarning(wt)) warn(wt);
hardsleep(60);
wt--;
}
shutdown(halttype);
return 0; /* Never happens */
}

505
src/sulogin.c Normal file
View File

@ -0,0 +1,505 @@
/*
* sulogin This program gives Linux machines a reasonable
* secure way to boot single user. It forces the
* user to supply the root password before a
* shell is started.
*
* If there is a shadow password file and the
* encrypted root password is "x" the shadow
* password will be used.
*
* Version: @(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl
*
* Copyright (C) 1998-2003 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <shadow.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#if defined(__GLIBC__)
# include <crypt.h>
#endif
#ifdef WITH_SELINUX
# include <selinux/selinux.h>
# include <selinux/get_context_list.h>
#endif
#define CHECK_DES 1
#define CHECK_MD5 1
#define F_PASSWD "/etc/passwd"
#define F_SHADOW "/etc/shadow"
#define BINSH "/bin/sh"
#define STATICSH "/bin/sash"
char *Version = "@(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl";
int timeout = 0;
int profile = 0;
#ifndef IUCLC
# define IUCLC 0
#endif
#if 0
/*
* Fix the tty modes and set reasonable defaults.
* (I'm not sure if this is needed under Linux, but..)
*/
void fixtty(void)
{
struct termios tty;
tcgetattr(0, &tty);
/*
* Set or adjust tty modes.
*/
tty.c_iflag &= ~(INLCR|IGNCR|IUCLC);
tty.c_iflag |= ICRNL;
tty.c_oflag &= ~(OCRNL|OLCUC|ONOCR|ONLRET|OFILL);
tty.c_oflag |= OPOST|ONLCR;
tty.c_cflag |= CLOCAL;
tty.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE;
/*
* Set the most important characters */
*/
tty.c_cc[VINTR] = 3;
tty.c_cc[VQUIT] = 28;
tty.c_cc[VERASE] = 127;
tty.c_cc[VKILL] = 24;
tty.c_cc[VEOF] = 4;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
tty.c_cc[VSTART] = 17;
tty.c_cc[VSTOP] = 19;
tty.c_cc[VSUSP] = 26;
tcsetattr(0, TCSANOW, &tty);
}
#endif
/*
* Called at timeout.
*/
void alrm_handler()
{
}
/*
* See if an encrypted password is valid. The encrypted
* password is checked for traditional-style DES and
* FreeBSD-style MD5 encryption.
*/
int valid(char *pass)
{
char *s;
int len;
if (pass[0] == 0) return 1;
#if CHECK_MD5
/*
* 3 bytes for the signature $1$
* up to 8 bytes for the salt
* $
* the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
*/
if (strncmp(pass, "$1$", 3) == 0) {
for(s = pass + 3; *s && *s != '$'; s++)
;
if (*s++ != '$') return 0;
len = strlen(s);
if (len < 22 || len > 24) return 0;
return 1;
}
#endif
#if CHECK_DES
if (strlen(pass) != 13) return 0;
for (s = pass; *s; s++) {
if ((*s < '0' || *s > '9') &&
(*s < 'a' || *s > 'z') &&
(*s < 'A' || *s > 'Z') &&
*s != '.' && *s != '/') return 0;
}
#endif
return 1;
}
/*
* Set a variable if the value is not NULL.
*/
void set(char **var, char *val)
{
if (val) *var = val;
}
/*
* Get the root password entry.
*/
struct passwd *getrootpwent(int try_manually)
{
static struct passwd pwd;
struct passwd *pw;
struct spwd *spw;
FILE *fp;
static char line[256];
static char sline[256];
char *p;
/*
* First, we try to get the password the standard
* way using normal library calls.
*/
if ((pw = getpwnam("root")) &&
!strcmp(pw->pw_passwd, "x") &&
(spw = getspnam("root")))
pw->pw_passwd = spw->sp_pwdp;
if (pw || !try_manually) return pw;
/*
* If we come here, we could not retrieve the root
* password through library calls and we try to
* read the password and shadow files manually.
*/
pwd.pw_name = "root";
pwd.pw_passwd = "";
pwd.pw_gecos = "Super User";
pwd.pw_dir = "/";
pwd.pw_shell = "";
pwd.pw_uid = 0;
pwd.pw_gid = 0;
if ((fp = fopen(F_PASSWD, "r")) == NULL) {
perror(F_PASSWD);
return &pwd;
}
/*
* Find root in the password file.
*/
while((p = fgets(line, 256, fp)) != NULL) {
if (strncmp(line, "root:", 5) != 0)
continue;
p += 5;
set(&pwd.pw_passwd, strsep(&p, ":"));
(void)strsep(&p, ":");
(void)strsep(&p, ":");
set(&pwd.pw_gecos, strsep(&p, ":"));
set(&pwd.pw_dir, strsep(&p, ":"));
set(&pwd.pw_shell, strsep(&p, "\n"));
p = line;
break;
}
fclose(fp);
/*
* If the encrypted password is valid
* or not found, return.
*/
if (p == NULL) {
fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
return &pwd;
}
if (valid(pwd.pw_passwd)) return &pwd;
/*
* The password is invalid. If there is a
* shadow password, try it.
*/
strcpy(pwd.pw_passwd, "");
if ((fp = fopen(F_SHADOW, "r")) == NULL) {
fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
return &pwd;
}
while((p = fgets(sline, 256, fp)) != NULL) {
if (strncmp(sline, "root:", 5) != 0)
continue;
p += 5;
set(&pwd.pw_passwd, strsep(&p, ":"));
break;
}
fclose(fp);
/*
* If the password is still invalid,
* NULL it, and return.
*/
if (p == NULL) {
fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
strcpy(pwd.pw_passwd, "");
}
if (!valid(pwd.pw_passwd)) {
fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
strcpy(pwd.pw_passwd, ""); }
return &pwd;
}
/*
* Ask for the password. Note that there is no
* default timeout as we normally skip this during boot.
*/
char *getpasswd(char *crypted)
{
struct sigaction sa;
struct termios old, tty;
static char pass[128];
char *ret = pass;
int i;
if (crypted[0])
printf("Give root password for maintenance\n");
else
printf("Press enter for maintenance\n");
printf("(or type Control-D to continue): ");
fflush(stdout);
tcgetattr(0, &old);
tcgetattr(0, &tty);
tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
tcsetattr(0, TCSANOW, &tty);
pass[sizeof(pass) - 1] = 0;
sa.sa_handler = alrm_handler;
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
if (timeout) alarm(timeout);
if (read(0, pass, sizeof(pass) - 1) <= 0)
ret = NULL;
else {
for(i = 0; i < sizeof(pass) && pass[i]; i++)
if (pass[i] == '\r' || pass[i] == '\n') {
pass[i] = 0;
break;
}
}
alarm(0);
tcsetattr(0, TCSANOW, &old);
printf("\n");
return ret;
}
/*
* Password was OK, execute a shell.
*/
void sushell(struct passwd *pwd)
{
char shell[128];
char home[128];
char *p;
char *sushell;
/*
* Set directory and shell.
*/
(void)chdir(pwd->pw_dir);
if ((p = getenv("SUSHELL")) != NULL)
sushell = p;
else if ((p = getenv("sushell")) != NULL)
sushell = p;
else {
if (pwd->pw_shell[0])
sushell = pwd->pw_shell;
else
sushell = BINSH;
}
if ((p = strrchr(sushell, '/')) == NULL)
p = sushell;
else
p++;
snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
/*
* Set some important environment variables.
*/
getcwd(home, sizeof(home));
setenv("HOME", home, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
if (!profile)
setenv("SHLVL","0",1);
/*
* Try to execute a shell.
*/
setenv("SHELL", sushell, 1);
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
#ifdef WITH_SELINUX
if (is_selinux_enabled > 0) {
security_context_t scon=NULL;
char *seuser=NULL;
char *level=NULL;
if (getseuserbyname("root", &seuser, &level) == 0)
if (get_default_context_with_level(seuser, level, 0, &scon) > 0) {
if (setexeccon(scon) != 0)
fprintf(stderr, "setexeccon faile\n");
freecon(scon);
}
free(seuser);
free(level);
}
#endif
execl(sushell, shell, NULL);
perror(sushell);
setenv("SHELL", BINSH, 1);
execl(BINSH, profile ? "-sh" : "sh", NULL);
perror(BINSH);
/* Fall back to staticly linked shell if both the users shell
and /bin/sh failed to execute. */
setenv("SHELL", STATICSH, 1);
execl(STATICSH, STATICSH, NULL);
perror(STATICSH);
}
void usage(void)
{
fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
}
int main(int argc, char **argv)
{
char *tty = NULL;
char *p;
struct passwd *pwd;
int c, fd = -1;
int opt_e = 0;
pid_t pid, pgrp, ppgrp, ttypgrp;
/*
* See if we have a timeout flag.
*/
opterr = 0;
while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {
case 't':
timeout = atoi(optarg);
break;
case 'p':
profile = 1;
break;
case 'e':
opt_e = 1;
break;
default:
usage();
/* Do not exit! */
break;
}
if (geteuid() != 0) {
fprintf(stderr, "sulogin: only root can run sulogin.\n");
exit(1);
}
/*
* See if we need to open an other tty device.
*/
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
if (optind < argc) tty = argv[optind];
if (tty) {
if ((fd = open(tty, O_RDWR)) < 0) {
perror(tty);
} else if (!isatty(fd)) {
fprintf(stderr, "%s: not a tty\n", tty);
close(fd);
} else {
/*
* Only go through this trouble if the new
* tty doesn't fall in this process group.
*/
pid = getpid();
pgrp = getpgid(0);
ppgrp = getpgid(getppid());
ioctl(fd, TIOCGPGRP, &ttypgrp);
if (pgrp != ttypgrp && ppgrp != ttypgrp) {
if (pid != getsid(0)) {
if (pid == getpgid(0))
setpgid(0, getpgid(getppid()));
setsid();
}
signal(SIGHUP, SIG_IGN);
ioctl(0, TIOCNOTTY, (char *)1);
signal(SIGHUP, SIG_DFL);
close(0);
close(1);
close(2);
close(fd);
fd = open(tty, O_RDWR);
ioctl(0, TIOCSCTTY, (char *)1);
dup(fd);
dup(fd);
} else
close(fd);
}
} else if (getpid() == 1) {
/* We are init. We hence need to set a session anyway */
setsid();
if (ioctl(0, TIOCSCTTY, (char *)1))
perror("ioctl(TIOCSCTTY)");
}
/*
* Get the root password.
*/
if ((pwd = getrootpwent(opt_e)) == NULL) {
fprintf(stderr, "sulogin: cannot open password database!\n");
sleep(2);
}
/*
* Ask for the password.
*/
while(pwd) {
if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
if (pwd->pw_passwd[0] == 0 ||
strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
sushell(pwd);
printf("Login incorrect.\n");
}
/*
* User pressed Control-D.
*/
return 0;
}

224
src/utmp.c Normal file
View File

@ -0,0 +1,224 @@
/*
* utmp.c Routines to read/write the utmp and wtmp files.
* Basically just wrappers around the library routines.
*
* Version: @(#)utmp.c 2.77 09-Jun-1999 miquels@cistron.nl
*
* Copyright (C) 1999 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <utmp.h>
#include "init.h"
#include "initreq.h"
#include "paths.h"
#if defined(__GLIBC__)
# if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) && defined(__powerpc__)
# define HAVE_UPDWTMP 0
# else
# define HAVE_UPDWTMP 1
# endif
#else
# define HAVE_UPDWTMP 0
#endif
/*
* Log an event in the wtmp file (reboot, runlevel)
*/
void write_wtmp(
char *user, /* name of user */
char *id, /* inittab ID */
int pid, /* PID of process */
int type, /* TYPE of entry */
char *line) /* Which line is this */
{
int fd;
struct utmp utmp;
struct utsname uname_buf;
struct timeval tv;
/*
* Try to open the wtmp file. Note that we even try
* this if we have updwtmp() so we can see if the
* wtmp file is accessible.
*/
if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND)) < 0) return;
#ifdef INIT_MAIN
/*
* Note if we are going to write a boot record.
*/
if (type == BOOT_TIME) wrote_wtmp_reboot++;
/*
* See if we need to write a reboot record. The reason that
* we are being so paranoid is that when we first tried to
* write the reboot record, /var was possibly not mounted
* yet. As soon as we can open WTMP we write a delayed boot record.
*/
if (wrote_wtmp_reboot == 0 && type != BOOT_TIME)
write_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
#endif
/*
* Zero the fields and enter new fields.
*/
memset(&utmp, 0, sizeof(utmp));
#if defined(__GLIBC__)
gettimeofday(&tv, NULL);
utmp.ut_tv.tv_sec = tv.tv_sec;
utmp.ut_tv.tv_usec = tv.tv_usec;
#else
time(&utmp.ut_time);
#endif
utmp.ut_pid = pid;
utmp.ut_type = type;
strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
strncpy(utmp.ut_id , id , sizeof(utmp.ut_id ));
strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
/* Put the OS version in place of the hostname */
if (uname(&uname_buf) == 0)
strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host));
#if HAVE_UPDWTMP
updwtmp(WTMP_FILE, &utmp);
#else
write(fd, (char *)&utmp, sizeof(utmp));
#endif
close(fd);
}
/*
* Write an entry to the UTMP file. For DEAD_PROCESS, put
* the previous ut_line into oldline if oldline != NULL.
*/
static void write_utmp(
char *user, /* name of user */
char *id, /* inittab ID */
int pid, /* PID of process */
int type, /* TYPE of entry */
char *line, /* LINE if used. */
char *oldline) /* Line of old utmp entry. */
{
struct utmp utmp;
struct utmp tmp;
struct utmp *utmptr;
struct timeval tv;
/*
* Can't do much if UTMP_FILE is not present.
*/
if (access(UTMP_FILE, F_OK) < 0)
return;
#ifdef INIT_MAIN
/*
* Note if we are going to write a boot record.
*/
if (type == BOOT_TIME) wrote_utmp_reboot++;
/*
* See if we need to write a reboot record. The reason that
* we are being so paranoid is that when we first tried to
* write the reboot record, /var was possibly not mounted
* yet. As soon as we can open WTMP we write a delayed boot record.
*/
if (wrote_utmp_reboot == 0 && type != BOOT_TIME)
write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL);
#endif
/*
* Fill out an utmp struct.
*/
memset(&utmp, 0, sizeof(utmp));
utmp.ut_type = type;
utmp.ut_pid = pid;
strncpy(utmp.ut_id, id, sizeof(utmp.ut_id));
#if defined(__GLIBC__)
gettimeofday(&tv, NULL);
utmp.ut_tv.tv_sec = tv.tv_sec;
utmp.ut_tv.tv_usec = tv.tv_usec;
#else
time(&utmp.ut_time);
#endif
strncpy(utmp.ut_user, user, UT_NAMESIZE);
if (line) strncpy(utmp.ut_line, line, UT_LINESIZE);
/*
* We might need to find the existing entry first, to
* find the tty of the process (for wtmp accounting).
*/
if (type == DEAD_PROCESS) {
/*
* Find existing entry for the tty line.
*/
setutent();
tmp = utmp;
if ((utmptr = getutid(&tmp)) != NULL) {
strncpy(utmp.ut_line, utmptr->ut_line, UT_LINESIZE);
if (oldline)
strncpy(oldline, utmptr->ut_line, UT_LINESIZE);
}
}
/*
* Update existing utmp file.
*/
setutent();
pututline(&utmp);
endutent();
}
/*
* Write a record to both utmp and wtmp.
*/
void write_utmp_wtmp(
char *user, /* name of user */
char *id, /* inittab ID */
int pid, /* PID of process */
int type, /* TYPE of entry */
char *line) /* LINE if used. */
{
char oldline[UT_LINESIZE];
/*
* For backwards compatibility we just return
* if user == NULL (means : clean up utmp file).
*/
if (user == NULL)
return;
oldline[0] = 0;
write_utmp(user, id, pid, type, line, oldline);
write_wtmp(user, id, pid, type, line && line[0] ? line : oldline);
}

298
src/utmpdump.c Normal file
View File

@ -0,0 +1,298 @@
/*
* utmpdump Simple program to dump UTMP and WTMP files in
* raw format, so they can be examined.
*
* Author: Miquel van Smoorenburg, <miquels@cistron.nl>
* Danek Duvall <duvall@alumni.princeton.edu>
*
* Version: @(#)utmpdump 2.79 12-Sep-2000
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2000 Miquel van Smoorenburg.
*
* Additional Copyright on this file 1998 Danek Duvall.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <utmp.h>
#include <time.h>
#include <ctype.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "oldutmp.h"
struct utmp
oldtonew(struct oldutmp src)
{
struct utmp dest;
memset(&dest, 0, sizeof dest);
dest.ut_type = src.ut_type;
dest.ut_pid = src.ut_pid;
dest.ut_time = src.ut_oldtime;
dest.ut_addr = src.ut_oldaddr;
strncpy(dest.ut_id, src.ut_id, 4);
strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
return dest;
}
struct oldutmp
newtoold(struct utmp src)
{
struct oldutmp dest;
memset(&dest, 0, sizeof dest);
dest.ut_type = src.ut_type;
dest.ut_pid = src.ut_pid;
dest.ut_oldtime = src.ut_time;
dest.ut_oldaddr = src.ut_addr;
strncpy(dest.ut_id, src.ut_id, 4);
strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
return dest;
}
char *
timetostr(const time_t time)
{
static char s[29]; /* [Sun Sep 01 00:00:00 1998 PST] */
if (time != 0)
strftime(s, 29, "%a %b %d %T %Y %Z", localtime(&time));
else
s[0] = '\0';
return s;
}
time_t
strtotime(const char *s_time)
{
struct tm tm;
memset(&tm, '\0', sizeof(struct tm));
if (s_time[0] == ' ' || s_time[0] == '\0')
return (time_t)0;
strptime(s_time, "%a %b %d %T %Y", &tm);
/* Cheesy way of checking for DST */
if (s_time[26] == 'D')
tm.tm_isdst = 1;
return mktime(&tm);
}
#define cleanse(x) xcleanse(x, sizeof(x))
void
xcleanse(char *s, int len)
{
for ( ; *s && len-- > 0; s++)
if (!isprint(*s) || *s == '[' || *s == ']')
*s = '?';
}
void
unspace(char *s, int len)
{
while (*s && *s != ' ' && len--)
++s;
if (len > 0)
*s = '\0';
}
void
print_utline(struct utmp ut)
{
char *addr_string, *time_string;
struct in_addr in;
in.s_addr = ut.ut_addr;
addr_string = inet_ntoa(in);
time_string = timetostr(ut.ut_time);
cleanse(ut.ut_id);
cleanse(ut.ut_user);
cleanse(ut.ut_line);
cleanse(ut.ut_host);
/* pid id user line host addr time */
printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15.15s] [%-28.28s]\n",
ut.ut_type, ut.ut_pid, ut.ut_id, 8, UT_NAMESIZE, ut.ut_user,
12, UT_LINESIZE, ut.ut_line, 20, UT_HOSTSIZE, ut.ut_host,
addr_string, time_string);
}
void
dump(FILE *fp, int forever, int oldfmt)
{
struct utmp ut;
struct oldutmp uto;
if (forever)
fseek(fp, -10 * (oldfmt ? sizeof uto : sizeof ut), SEEK_END);
do {
if (oldfmt)
while (fread(&uto, sizeof uto, 1, fp) == 1)
print_utline(oldtonew(uto));
else
while (fread(&ut, sizeof ut, 1, fp) == 1)
print_utline(ut);
if (forever) sleep(1);
} while (forever);
}
/* This function won't work properly if there's a ']' or a ' ' in the real
* token. Thankfully, this should never happen. */
int
gettok(char *line, char *dest, int size, int eatspace)
{
int bpos, epos, eaten;
char *t;
bpos = strchr(line, '[') - line;
if (bpos < 0) {
fprintf(stderr, "Extraneous newline in file. Exiting.");
exit(1);
}
line += 1 + bpos;
epos = strchr(line, ']') - line;
if (epos < 0) {
fprintf(stderr, "Extraneous newline in file. Exiting.");
exit(1);
}
line[epos] = '\0';
eaten = bpos + epos + 1;
if (eatspace)
if ((t = strchr(line, ' ')))
*t = 0;
strncpy(dest, line, size);
return eaten + 1;
}
void
undump(FILE *fp, int forever, int oldfmt)
{
struct utmp ut;
struct oldutmp uto;
char s_addr[16], s_time[29], *linestart, *line;
int count = 0;
line = linestart = malloc(1024 * sizeof *linestart);
s_addr[15] = 0;
s_time[28] = 0;
while(fgets(linestart, 1023, fp))
{
line = linestart;
memset(&ut, '\0', sizeof(ut));
sscanf(line, "[%hd] [%d] [%4c] ", &ut.ut_type, &ut.ut_pid, ut.ut_id);
line += 19;
line += gettok(line, ut.ut_user, sizeof(ut.ut_user), 1);
line += gettok(line, ut.ut_line, sizeof(ut.ut_line), 1);
line += gettok(line, ut.ut_host, sizeof(ut.ut_host), 1);
line += gettok(line, s_addr, sizeof(s_addr)-1, 1);
line += gettok(line, s_time, sizeof(s_time)-1, 0);
ut.ut_addr = inet_addr(s_addr);
ut.ut_time = strtotime(s_time);
if (oldfmt) {
uto = newtoold(ut);
fwrite(&uto, sizeof(uto), 1, stdout);
} else
fwrite(&ut, sizeof(ut), 1, stdout);
++count;
}
free(linestart);
}
void
usage(int result)
{
printf("Usage: utmpdump [ -froh ] [ filename ]\n");
exit(result);
}
int main(int argc, char **argv)
{
int c;
FILE *fp;
int reverse = 0, forever = 0, oldfmt = 0;
while ((c = getopt(argc, argv, "froh")) != EOF) {
switch (c) {
case 'r':
reverse = 1;
break;
case 'f':
forever = 1;
break;
case 'o':
oldfmt = 1;
break;
case 'h':
usage(0);
break;
default:
usage(1);
}
}
if (optind < argc) {
fprintf(stderr, "Utmp %sdump of %s\n", reverse ? "un" : "", argv[optind]);
if ((fp = fopen(argv[optind], "r")) == NULL) {
perror("Unable to open file");
exit(1);
}
}
else {
fprintf(stderr, "Utmp %sdump of stdin\n", reverse ? "un" : "");
fp = stdin;
}
if (reverse)
undump(fp, forever, oldfmt);
else
dump(fp, forever, oldfmt);
fclose(fp);
return 0;
}

123
src/wall.c Normal file
View File

@ -0,0 +1,123 @@
/*
* wall.c Write to all users logged in.
*
* Usage: wall [text]
*
* Version: @(#)wall 2.79 12-Sep-2000 miquels@cistron.nl
*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2000 Miquel van Smoorenburg.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <syslog.h>
char *Version = "@(#) wall 2.79 12-Sep-2000 miquels@cistron.nl";
#define MAXLEN 4096
#define MAXLINES 20
extern void wall(char *, int, int);
int main(int argc, char **argv)
{
char buf[MAXLEN];
char line[83];
int i, f, ch;
int len = 0;
int remote = 0;
char *p;
char *whoami;
struct passwd *pwd;
buf[0] = 0;
if ((pwd = getpwuid(getuid())) == NULL) {
if (getuid() == 0)
whoami = "root";
else {
fprintf(stderr, "You don't exist. Go away.\n");
exit(1);
}
} else
whoami = pwd->pw_name;
while((ch = getopt(argc, argv, "n")) != EOF)
switch(ch) {
case 'n':
/*
* Undocumented option for suppressing
* banner from rpc.rwalld. Only works if
* we are root or if we're NOT setgid.
*/
if (geteuid() != 0 && getgid() != getegid()) {
fprintf(stderr, "wall -n: not priviliged\n");
exit(1);
}
remote = 1;
break;
default:
fprintf(stderr, "usage: wall [message]\n");
return 1;
break;
}
if ((argc - optind) > 0) {
for(f = optind; f < argc; f++) {
len += strlen(argv[f]) + 1;
if (len >= MAXLEN-2) break;
strcat(buf, argv[f]);
if (f < argc-1) strcat(buf, " ");
}
strcat(buf, "\r\n");
} else {
while(fgets(line, 80, stdin)) {
/*
* Make sure that line ends in \r\n
*/
for(p = line; *p && *p != '\r' && *p != '\n'; p++)
;
strcpy(p, "\r\n");
len += strlen(line);
if (len >= MAXLEN) break;
strcat(buf, line);
}
}
i = 0;
for (p = buf; *p; p++) {
if (*p == '\n' && i++ > MAXLINES) {
*++p = 0;
break;
}
}
openlog("wall", LOG_PID, LOG_USER);
syslog(LOG_INFO, "wall: user %s broadcasted %d lines (%d chars)",
whoami, i, strlen(buf));
closelog();
unsetenv("TZ");
wall(buf, 0, remote);
/*NOTREACHED*/
return 0;
}