login.c: fchown is not defined in my environment, the two lines around
#46 were commented out in the previous version. I commented them out
again, but I believe there is an other solution?
ps.c: and I can't compile it, what are these two <linuxmt/mem.h> and
<linuxmt/sched.h> ?
init.c: here is my new version. I am prepared to receive lots of
complains, it works good enough for me, but I can imagine some of you
expect more. it uses /etc/inittab, this works nicely, and is designed
to allow changing the current runlevel, but somehow that doesn't work,
anyone wanting to help? I tried to minimize memory usage, the way I
chose was to hold very little information about the 8 possible children
and read /etc/inittab each time something happens to a child. If you
feel that 8 children are too few for your init process, you can increase
that value or we could make that more flexible... But I thought someone
(Al?) said that in ELKS a process statically allocates memory on startup
so I don't think this added flexibility makes much sense.
well, here is the source, I can't check it in into CVS myself.
/*
* init A System-V init Clone.
*
* Usage: /bin/init
* init [0123456]
*
* 1999-11-07 [EMAIL PROTECTED]
*
* Copyright 1999 Mario Frasca
*
* 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.
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <utmp.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
#include <memory.h>
#include <errno.h>
/*#define DEBUG*/
#if 0
#define _(A) A
#else
#define _(A) ()
#endif
#define FLAG_RESPAWN 1
#define FLAG_WAIT 2
#define RUNLEVELS 12
#define BUFSIZE 256
#define INITTAB "/etc/inittab"
#define INITLVL "/etc/initlvl"
#define SHELL "/bin/sh"
#define GETTY "/bin/getty"
#define DEVTTY "/dev/tty1"
#define MAXCHILD 8
/* 'hashed' strings */
#define RESPAWN 362
#define WAIT 122
#define ONCE 62
#define BOOT 147
#define BOOTWAIT 465
#define POWERFAIL 403
#define POWERFAILNOW 951
#define POWERWAIT 577
#define POWEROKWAIT 829
#define CTRLALTDEL 504
#define OFF 39
#define ONDEMAND 240
#define INITDEFAULT 707
#define SYSINIT 398
#define KBREQUEST 622
int hash(string)
char *string;
{
char *p;
int result = 0, i=1;
p = string;
while (*p)
result += ( (*p++)-'a')*(i++);
return result;
}
/* `gently' exit */
#if 1
# define PANIC0 fputs("init panic\n", stderr),fflush(stderr),exit(1)
# define PANIC(a) fputs("init panic\n", stderr),fputs(a, stderr),exit(1)
#else
# define PANIC(a) exit(1)
#endif
#ifdef DEBUG
#define FPUTS(A) fputs(A,stderr);
#define FPUTC(A) fputc(A,stderr);
#define FPUTD(A) fprintf(stderr, "%d", A);
#else
#define FPUTS(A)
#define FPUTC(A)
#define FPUTD(A)
#endif
/*
each of the entries from inittab corresponds to a child, each of which:
has a unique 2 chars identifier.
is allowed to run in some run-levels.
might need to be waited for completion when spawned.
might be running or not (pid different from zero).
might have to been respawned.
was respawned at a certain point in time.
for each running child, we keep the pid assigned to a given id.
We take this information each time from the INITTAB file.
*/
struct tabentry
{
char id[3];
pid_t pid;
};
struct tabentry
children[MAXCHILD],
*nextchild=children, *thisOne;
char runlevel;
char prevRunlevel;
struct utmp utentry;
void parseLine(line, foo)
const char* line;
void foo();
{
char *a[4];
int k = 0, action;
char buf[256], *p;
strcpy(buf, line);
a[k++] = p = buf;
while(k<4)
{
/* looking for the k-th ':' */
while(*p && *p != ':') p++;
*p = 0;
a[k++] = ++p;
}
foo(a);
}
void scanFile(foo)
void foo();
{
int f, left;
char buf[BUFSIZE], *line, *next;
f = open(INITTAB, O_RDONLY);
if(-1 == f)
PANIC0;
left = read(f, buf, BUFSIZE);
line = strtok(buf, "\n");
next = strtok(NULL, "\n");
while (left)
{
if (!next)
{
if(line == buf)
PANIC0;
memmove(buf, line, left);
left += read(f, buf+left, BUFSIZE-left);
line = buf;
next = strtok(buf, "\n");
}
else
{
parseLine(line, foo);
left -= next-line;
line = next;
next = strtok(NULL, "\n");
}
}
close(f);
}
/* returns a pointer to the child or NULL */
struct tabentry * matchPid(pid)
pid_t pid;
{
struct tabentry *i=nextchild;
while(i!=children)
if((--i)->pid == pid) return i;
return 0;
}
/* returns a pointer to the child or NULL */
struct tabentry * matchId(id)
char * id;
{
struct tabentry * i=nextchild;
while(i!=children)
if(!strcmp((--i)->id, id)) return i;
return 0;
}
/* appends child information in the array */
void appendChild (id, pid)
char * id;
pid_t pid;
{
if(MAXCHILD == nextchild-children)
PANIC("too many children");
memcpy(nextchild->id, id, 2);
nextchild->id[2] = 0;
nextchild->pid = pid;
nextchild++;
}
/* removes child information from the array */
void removeChild (pos)
struct tabentry * pos;
{
if(pos-children >= nextchild-children)
PANIC("unexistent child");
memcpy(pos, --nextchild, sizeof (struct tabentry) );
}
void doSleep(int sec)
{
/*
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = 0;
while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
;
*/
}
pid_t respawn(a)
const char **a;
{
int pid, status;
FPUTS("spawning \"")
FPUTS(a[3])
FPUTS("\"\n")
if (a[3] == 0)
return 1;
pid = fork();
if (-1 == pid)
PANIC0;
if (0 == pid)
{
char *argv[4], buf[128];
strcpy(buf, a[3]);
if(!strncmp(buf, GETTY, sizeof GETTY -1))
{
int fd;
char *devtty;
devtty = strchr(buf, ' ');
if(!devtty)
PANIC0;
*(devtty++) = 0;
if ((fd = open(devtty, O_RDWR)) < 0)
PANIC0;
dup2(fd ,STDIN_FILENO);
dup2(fd ,STDOUT_FILENO);
dup2(fd ,STDERR_FILENO);
argv[0] = GETTY;
argv[1] = NULL;
execv(argv[0], argv);
}
else
{
int fd;
if ((fd = open(DEVTTY, O_RDWR)) < 0)
PANIC0;
dup2(fd ,STDIN_FILENO);
dup2(fd ,STDOUT_FILENO);
dup2(fd ,STDERR_FILENO);
argv[0] = SHELL;
argv[1] = "-e";
argv[2] = buf;
argv[3] = strtok(buf, " ");
argv[4] = NULL;
execv(argv[0], argv);
}
PANIC0;
}
FPUTS("owner process owns ")
FPUTD(pid)
FPUTC('\n')
/* here I must do something about utmp */
return pid;
}
void passOne(a)
char **a;
{
pid_t pid;
switch(hash(a[2]))
{
case INITDEFAULT:
runlevel = a[1][0];
break;
case SYSINIT:
pid = respawn(a);
while(pid != wait());
break;
default:
/* ignore */
;
}
}
void getRunlevel(a)
char **a;
{
if(INITDEFAULT == hash(a[2]))
{
runlevel = a[1][0];
}
}
void exitRunlevel(a)
char **a;
{
FPUTS(a[0]) FPUTC(':') FPUTS(a[1]) FPUTC(':') FPUTS(a[2]) FPUTC(':')
FPUTS(a[3])
if( a[1][0] && !strchr(a[1], runlevel) ) /*not autorized*/
{
pid_t pid;
struct tabentry *child;
FPUTS(" stop it!")
/* if running, terminate it gently*/
child = matchId(a[0]);
if(!child) {
FPUTS(" not running\n")
return;
}
if(!child->pid) {
FPUTS(" not running\n")
return;
}
kill(child->pid, SIGTERM);
doSleep(2); /* give it the time */
/* if still running, kill it right away */
child = matchId(a[0]);
if(!child) return;
if(!child->pid) return;
kill(child->pid, SIGKILL);
}
FPUTC('\n')
}
void enterRunlevel(a)
char **a;
{
pid_t pid;
FPUTS(a[0]) FPUTC(':') FPUTS(a[1]) FPUTC(':') FPUTS(a[2]) FPUTC(':')
FPUTS(a[3])
if( !a[1][0] || strchr(a[1], runlevel) ) /*autorized*/
{
int andWait=0;
/* if not running, spawn it */
if ( !matchId(a[0]) )
switch(hash(a[2]))
{
case WAIT:
andWait = 1;
case RESPAWN:
case ONCE:
pid = respawn(a);
if(andWait)
while(pid != wait());
else
appendChild(a[0], pid);
break;
default:
{
FPUTS("discarded\n")
}
}
else
{
FPUTS("already running!\n")
}
}
}
void spawnThisOne(a)
char **a;
{
if( !strncmp(a[0], thisOne->id, 2) )
{
switch(hash(a[2]))
{
case RESPAWN:
case ONDEMAND:
thisOne->pid = respawn(a);
break;
default:
removeChild(thisOne);
}
strcpy(utentry.ut_line, strstr(a[3], "/tty")+1);
time(&utentry.ut_time);
utentry.ut_id[0] = a[0][0];
utentry.ut_id[1] = a[0][1];
utentry.ut_pid = thisOne->pid;
setutent();
pututline(&utentry);
endutent();
}
}
void handle_signal(sig)
int sig;
{
FPUTS("got signaled!\n")
switch(sig)
{
case SIGHUP:
/* got signaled by another instance of init, change runlevel! */
{
prevRunlevel = runlevel;
scanFile(getRunlevel);
if (runlevel != prevRunlevel)
{
/* -stop all running children not needed in new run-level */
scanFile(exitRunlevel);
/* -start all non running children needed in new run-level */
scanFile(enterRunlevel);
}
}
break;
}
}
int main(argc, argv)
char ** argv;
int argc;
{
int fd;
#ifdef DEBUG
fd = open(DEVTTY, 2);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
FPUTS("entered /bin/init\n")
#endif
memset(&utentry, 0, sizeof(struct utmp));
utentry.ut_type = INIT_PROCESS;
time(&utentry.ut_time);
utentry.ut_id[0] = 'l';
utentry.ut_id[1] = '1';
utentry.ut_pid = getpid();
strcpy(utentry.ut_user, "INIT");
setutent();
pututline(&utentry);
/* am I the No.1 init? */
if(getpid() == 1)
{
struct tabentry *entry;
/* signal(SIGALRM, handle_signal); */
signal(SIGHUP, handle_signal);
/* signal(SIGINT, handle_signal); */
/* signal(SIGCHLD, handle_signal); */
/* signal(SIGPWR, handle_signal); */
/* signal(SIGWINCH, handle_signal); */
/* signal(SIGUSR1, handle_signal); */
/* signal(SIGSTOP, handle_signal); */
/* signal(SIGTSTP, handle_signal); */
/* signal(SIGCONT, handle_signal); */
/* signal(SIGSEGV, handle_signal); */
setutent();
/* get runlevel & spawn sysinit */
FPUTS("scanfile - passOne\n")
scanFile(passOne);
FPUTS("entered runlevel ")
FPUTC(runlevel)
FPUTC('\n')
/* spawn needed children */
FPUTS("scanfile - enterRunlevel\n")
scanFile(enterRunlevel);
endutent();
/* wait for signals. */
while(1)
{
pid_t pid;
FPUTS("about to go waiting...\n")
pid = wait();
FPUTS("and ")
FPUTD(pid)
FPUTS(" came out\n")
if(-1 == pid)
continue;
FPUTS("child ")
FPUTD(pid)
FPUTS(" died...\n")
thisOne = matchPid(pid);
if(!thisOne)
continue;
FPUTS("scanfile - spawnThisOne\n")
scanFile(spawnThisOne);
}
}
else
{
/* store the new run-level into /etc/initrunlvl */
int f = open(INITLVL, O_WRONLY);
write(f, argv[1], 1);
close(f);
FPUTS("change request to ")
FPUTC(argv[1][0])
FPUTC('\n')
/* signal (SIGHUP) the No.1 init that we must switch run-level. */
kill(1, SIGHUP);
}
return 0;
}