import cinit from unix.schottelius.org

Signed-off-by: Nico Schottelius <nico@ikn.schottelius.org>
This commit is contained in:
Nico Schottelius 2009-09-16 12:53:45 +02:00
commit 423ba10303
13396 changed files with 269468 additions and 0 deletions

View file

@ -0,0 +1,161 @@
#
# cinit
#
# Nico Schottelius
#
# Don't edit Makefiles, use conf/* for configuration.
#
################################################################################
#
# Build tools / locations
#
CC=../tmpbin/cc
CFLAGS=
LD=../tmpbin/ld
LDFLAGS=
STRIP=../tmpbin/strip
SBIN=../sbin
DESTDIR=
#DESTDIR=/home/user/nico/emu/dst
################################################################################
#
# All objects / binaries
# depend on headers. More or less. FIXME: use gcc -M
#
BIN=halt.kill poweroff.kill reboot.kill cmd
CINIT=cinit
ALLBIN=${BIN} ${CINIT}
# headers
CONFIG_H=include/config.h
CINIT_HEADERS=${shell cat include/listing}
# objects
CINIT_OBJ=${shell cat object_lists/cinit}
HALTKILL_OBJ=${shell cat object_lists/halt.kill}
POWEROFFKILL_OBJ=${shell cat object_lists/poweroff.kill}
REBOOTKILL_OBJ=${shell cat object_lists/reboot.kill}
CMD_OBJ=${shell cat object_lists/cmd}
#
# All objects
#
OBJ=${CINIT_OBJ} ${HALTKILL_OBJ} ${POWEROFFKILL_OBJ} ${REBOOTKILL_OBJ}
################################################################################
#
# End user target
#
#all: cinit cservice ccontrol sizecheck docs
all: ${ALLBIN}
################################################################################
#
# Generic
#
${OBJ}: ${CINIT_HEADERS}
%.o: %.c
${CC} -c -o $@ $<
################################################################################
#
# First do configuration, so we include the right variables
#
Makefile: .configured
.configured: ../conf/*
@../bin/cinit.configure.os
@../bin/cinit.configure.tools
@../bin/cinit.configure.ipc
@../bin/cinit.configure.mark
${CINIT_OBJ}: ${CONFIG_H}
${CONFIG_H}: ../conf/*
../scripts/cinit.mkheader > ${CONFIG_H}
################################################################################
#
# Install targets
#
#install: install-dir cinit cservice ccontrol
install: install-cinit install-utilities
install-sbin:
install -d ${DESTDIR}/sbin
install-utilities: install-sbin ${BIN}
@echo '*** Installing utilities ***'
install ${BIN} ${DESTDIR}/sbin
install-cinit: install-sbin cinit
@echo '*** Installing cinit ***'
@echo "Need to delete cinit before reinstalling it {text file busy problem}"
rm -f ${DESTDIR}/sbin/cinit
install cinit ${DESTDIR}/sbin
# FIXME: target broken
install-miniconf:
./bin/cinit.install.miniconf
# FIXME: target broken
install-dir:
./bin/cinit.install.dir
################################################################################
#
# Build targets
#
cinit: ${CINIT_OBJ}
${LD} $^ -o $@
halt.kill: ${HALTKILL_OBJ}
${LD} $^ -o $@
poweroff.kill: ${POWEROFFKILL_OBJ}
${LD} $^ -o $@
reboot.kill: ${REBOOTKILL_OBJ}
${LD} $^ -o $@
cmd: ${CMD_OBJ}
${LD} $^ -o $@
################################################################################
#
# Internal test targets
#
uml: cinit cmd
../../vm/uml/uml-mount.sh
cp cinit cmd ../../vm/uml/root/sbin/
../../vm/uml/uml-umount.sh
umlstart: uml
../../vm/uml/uml-start.sh
################################################################################
#
# Clenaup targets
#
.PHONY: dist
dist: distclean
.PHONY: distclean
distclean: clean
rm -f os/current ipc/current .configured
.PHONY: clean
clean:
rm -f ../tmpbin/*.configured
rm -f ${BIN} ${CINIT_OBJ} ${CINIT}
rm -f client/*.o test/*.o

View file

@ -0,0 +1,27 @@
#
# Makefile for cinit tests
#
# Nico Schottelius
#
# Don't edit Makefiles, use conf/* for configuration.
#
TEST_BUILD_ARGV=test/test_build_argv.o core/build_argv.o
PROGS=test_build_argv test_build_argv_link
tests: $(PROGS)
test_build_argv: test/test_build_argv.o core/build_argv.o
test_build_argv_link: test/test_build_argv+link.o core/build_argv.o
test_gen_svc_tree: test/test_gen_svc_tree.o svc/list_display_all.o \
svc/list_display_all.o \
svc/list_display_all.o \
svc/list_display_all.o \
svc/list_display_all.o \
svc/gen_svc_tree.o \
generic/mini_printf.o \
svc/list_display_all.o
test_openreadclose: test/test_openreadclose.o generic/openreadclose.o

View file

@ -0,0 +1,81 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit (at) schottelius.org)
*
* part of cLinux/cinit
*
* Communication defines
*/
#ifndef CINIT_COMM_HEADER
#define CINIT_COMM_HEADER
#include <limits.h> /* PATH_MAX */
#include <sys/types.h> /* pid_t */
/***********************************************************************
* Commands the clients may issue to us
* maximum number of commands: 2^8 = 256
*/
enum commands {
CMD_MIN='A', /* minimum command number */
CMD_SVC_START, /* the client wants US to start a service */
CMD_SVC_START_ONLY, /* start this service without dependencies */
CMD_SVC_START_NEEDS, /* start this service, needs, but no wants */
CMD_SVC_STOP, /* stop svc and all svcs that need it */
CMD_SVC_STOP_ONLY, /* we should stop _only_ this service */
CMD_SVC_STOP_WANTS, /* stop svc, all svcs that need or want it */
CMD_CHG_STAT, /* the client reports a status change */ /* FIXME: NEEDED? */
CMD_RESCUE, /* we should start the rescue mode */ /* UNIMPLEMENTED */
CMD_HALT, /* halt the system */
CMD_REBOOT, /* reboot the system */
CMD_POWEROFF, /* poweroff the system */
CMD_WBOOT, /* shutdown and restart everything */ /* UNIMPLEMENTED */
CMD_INFO, /* send information about that service */ /* UNIMPLEMENTED */
CMD_MAX , /* maximum command number */
};
/* old
RT_ERR_COMM, * communication failed *
RT_ERR, * service starting failed *
RT_UNSPEC, * some kind of error, unspecified *
RT_SUCCESS, * successfully started: respawning or once *
RT_SVC_FAILED, * tried earlier, service failed, won't retry *
*/
/***********************************************************************
* client issues a command: start_command
*/
struct s_cmd {
char cmd;
pid_t pid;
};
/***********************************************************************
* messages from the client
* Prefix: qst_ (question)
*/
struct msg_client {
pid_t pid; /* pid of the telling client */
char cmd; /* which cmd is issued to us */
char status; /* status of the service */
char svc[PATH_MAX]; /* name of the service */
char svc_orig[PATH_MAX]; /* the service, which wants to start us */
};
/***********************************************************************
* messages from the server
* Prefix: asw_ (answer)
*/
/***********************************************************************
* return short status
*/
struct asw_sstatus {
long mtype;
char status;
char msg[PATH_MAX];
};
#endif

View file

@ -0,0 +1,70 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* change status of a service
* part of cinit
*/
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include "cinit.h"
/* client:
* svc = service name
* status = status
* pid = pid
* sock2 = sock
* action = ACT_WRITE
* return: error code
*
* server:
* svc = buffer
* status = where to save status
* svc = bufferTH_MAX
* pid = where to save pid
* sock2 = nsock
* action = ACT_READ
* return: read service lenght
*/
int do_change_status(char *svc, char *status, pid_t *pid, int sock2, int action)
{
int tmp;
ssize_t (*fpoint)(int,void* ,size_t);
if(action == ACT_SERV) {
fpoint = read;
} else {
fpoint = ( ssize_t (*)(int, void*, size_t) ) write;
tmp = strlen(svc);
}
if(fpoint(sock2,&tmp,sizeof(tmp)) == -1) { /* length */
perror(MSG_ERR_IO);
return 0;
}
if(tmp > PATH_MAX) {
return 0;
}
if(fpoint(sock2,svc,tmp) == -1) { /* write service name */
perror(MSG_ERR_IO);
return 0;
}
if(fpoint(sock2,status,sizeof(*status)) == -1) { /* status */
perror(MSG_ERR_IO);
return 0;
}
if(fpoint(sock2,pid,sizeof(*pid)) == -1) { /* PID */
perror(MSG_ERR_IO);
return 0;
}
return tmp;
}

View file

@ -0,0 +1,33 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* write result of action
* part of cinit
*/
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "cinit.h"
/* one handler for read and write! */
char do_result(int nsock, char *value)
{
ssize_t (*fpoint)(int,void* ,size_t);
char buf;
if(value == NULL) { /* client */
value = &buf;
fpoint = read;
} else {
fpoint = ( ssize_t (*)(int, void*, size_t) ) write;
}
if(fpoint(nsock,value,1) == -1) { /* result */
perror(MSG_ERR_IO);
return RT_ERR_COMM;
}
return *value;
}
/* returns cinit-0.2-style return codes */

View file

@ -0,0 +1,51 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* try to start a service
* part of cinit
*/
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include "cinit.h"
/* serv:
* get buf
* return length
*
* client:
* print svc
* return errorcode
*/
int do_svc_name(int sock2, char *svc, int action)
{
int tmp;
ssize_t (*fpoint)(int,void* ,size_t);
/* set pointers */
if(action == ACT_CLIENT) {
fpoint = ( ssize_t (*)(int, void*, size_t) ) write;
tmp = strlen(svc);
} else {
fpoint = read;
}
/* read / write lenght */
if( fpoint(sock2,&tmp,sizeof(tmp)) == -1) {
perror(MSG_ERR_IO);
return 0;
}
if(tmp > PATH_MAX) {
return 0;
}
/* write/read service name */
if( fpoint(sock2,svc,tmp) == -1) {
perror(MSG_ERR_IO);
return 0;
}
return tmp;
}

View file

@ -0,0 +1,264 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run_svc
* part of cinit
*/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "cinit.h"
/***********************************************************************
* exec_svc: exec service abspath C_ON or C_OFF
*/
inline pid_t exec_svc(char *abspath, int action)
{
int tmp;
char *p, pathtmp[PATH_MAX];
char *sbuf = NULL, **nargv = NULL, **nenv = NULL;
int fd, argc;
struct stat buf;
cpid = fork();
if( cpid == -1 ) {
perror(MSG_ERR_FORK);
return 0;
}
/***** PARENT ******/
if(cpid > 0) {
waitpid(cpid,&tmp,0);
if( WIFEXITED(tmp) ) {
if( ! WEXITSTATUS(tmp) ) {
return cpid;
}
}
SERVICE_LOG(abspath,LOG_SVC_FAIL);
return 0;
}
/*********** CHILD EXECUTION ***********/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(action == CMD_START_SVC) {
strcat(pathtmp,C_ON);
} else {
strcat(pathtmp,C_OFF);
}
/* readlink retrieves real name, if it is a symlink */
if ( ( tmp = readlink(pathtmp,pathtmp,PATH_MAX) ) == -1) {
/* nothing there? fine, exit */
if(errno == ENOENT) {
_exit(0);
} else if (errno != EINVAL) {
perror(MSG_READLINK);
_exit(1);
}
/* restore original name, file is not a link */
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(action == CMD_START_SVC) {
strcat(pathtmp,C_ON);
} else {
strcat(pathtmp,C_OFF);
}
tmp = strlen(pathtmp);
} else {
/* add '\0', readlink forgets it */
pathtmp[tmp] = '\0';
}
++tmp; /* the byte to add to memory for \0;
neither readlink nor strlen count the \0 */
/********** build argv0 ********/
nargv = (char **) malloc( sizeof(char *) );
if(nargv == NULL) _exit(1);
*nargv = (char *) malloc( tmp );
if(*nargv == NULL) _exit(1);
strcpy(*nargv,pathtmp);
/********************** read params *********************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(action == CMD_START_SVC) {
strcat(pathtmp,C_ONARG);
} else {
strcat(pathtmp,C_OFFARG);
}
/* open params file */
if( !stat(pathtmp,&buf) ) {
fd = open(pathtmp,O_RDONLY);
if(fd == -1) {
perror(MSG_ERR_OPEN);
_exit(1);
}
argc = 0;
/* fill sbuf with content */
while ( (tmp = read(fd,pathtmp,PATH_MAX) ) != 0 ) {
if(tmp == -1) {
perror(MSG_ERR_READ);
_exit(1);
}
sbuf = realloc(sbuf,argc + tmp + 1);
strncpy(&sbuf[argc],pathtmp,tmp);
argc += tmp;
}
close(fd);
if(argc) {
sbuf[argc] = '\0'; /* terminate string */
}
} else {
sbuf = NULL;
}
/************** build string **************/
/* The idea is to reuse the allocated memory. We'll simply
* replace the \n with \0 and set a char* to it.
* We'll lose the last byte (the initial \0), but we
* don't care, as we die some seconds later with execv()
* oh, we'll only lose it, if the file is terminated by \n */
argc = 1; /* argv0 */
while( sbuf != NULL) {
p = strchr(sbuf,'\n');
nargv = realloc(nargv, sizeof(char *) * (argc + 1));
if(nargv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
/* set to the beginning */
nargv[argc] = sbuf;
/* if we found \n */
if(p != NULL) {
*p = '\0';
} else {
/* set to the end of sbuf, not to the \0, but one before */
p = sbuf + (strlen(sbuf)-1);
}
/* if next byte is 0, the end of string is found */
if( *(p+1) == '\0') {
sbuf = NULL;
} else {
sbuf = p+1;
}
++argc;
}
/************ close argv list **************/
nargv = realloc(nargv, sizeof(char *) * (argc + 1)); /* 1: NULL-pointer */
if(nargv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
nargv[argc] = NULL; /* terminate argv list */
/********************** read environment *********************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(action == CMD_START_SVC) {
strcat(pathtmp,C_ONENV);
} else {
strcat(pathtmp,C_OFFENV);
}
argc = 0;
sbuf = NULL;
if( !stat(pathtmp,&buf) ) {
fd = open(pathtmp,O_RDONLY);
/* file exists, failing to open it is an error */
if(fd == -1) {
perror(MSG_ERR_OPEN);
_exit(1);
}
while ( (tmp = read(fd,pathtmp,PATH_MAX) ) != 0 ) {
if(tmp == -1) {
perror(MSG_ERR_READ);
_exit(1);
}
sbuf = realloc(sbuf,argc + tmp + 1);
strncpy(&sbuf[argc],pathtmp,tmp);
argc += tmp;
}
close(fd);
if(argc)
sbuf[argc] = '\0'; /* terminate string */
}
/************** build environment string **************/
argc = 0;
while( sbuf != NULL ) {
p = strchr(sbuf,'\n');
nenv = realloc(nenv, sizeof(char *) * (argc + 1));
if(nenv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
nenv[argc] = sbuf;
/* if we found \n */
if(p != NULL) {
*p = '\0';
} else {
/* set to the end of sbuf, not to the \0, but one before */
p = sbuf + (strlen(sbuf)-1);
}
if( *(p+1) == '\0') {
sbuf = NULL;
} else {
sbuf = p+1;
}
++argc;
}
/************ close env list **************/
nenv = realloc(nenv, sizeof(char *) * (argc + 1));
if(nenv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
nenv[argc] = NULL;
/****************** EXECUTE ********************/
execve(nargv[0],nargv,nenv);
/* we should never reach this block */
P_EXEC_FAILED(nargv[0]);
perror(MSG_ERR_EXECVE);
/* FIXME: remove debug, remove double printing without loosing info */
sleep(3); /* debug */
_exit(1);
}

View file

@ -0,0 +1,29 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* tell cinit that I want change the status of a service
* part of cinit
*/
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include "cinit.h"
/* FIXME: change return code validation */
int msg_change_status(char *svc, char status, pid_t pid)
{
if(!begin_msg(CMD_CHG_STATUS)) {
return RT_ERR_COMM;
}
if(!do_change_status(svc,&status,&pid,sock,ACT_CLIENT)) {
return 0;
}
if(!do_result(sock,NULL)) {
return 0;
}
return 1;
}

View file

@ -0,0 +1,23 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* tell cinit that I want to start a service
* part of cinit
*/
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "cinit.h"
/* **********************************************************************
* action: 1=on, 0=off
*/
int msg_svc_on_off(char *svc, char action)
{
if(!begin_msg(action)) return RT_ERR_COMM;
if(!do_svc_name(sock,svc,ACT_CLIENT)) return RT_ERR_COMM;
return (int) do_result(sock,NULL);
}
/* returns cinit-0.2-style return codes */

View file

@ -0,0 +1,99 @@
/*
* (c) 2005,2006 Nico Schottelius (nico-linux at schottelius.org)
* respawn_svc
* part of cinit
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "cinit.h"
/* run a service, gets (relative or absolute) path */
pid_t respawn_svc(char *abspath)
{
pid_t pid;
int tmp;
int pipefd[2];
struct sigaction sa;
char delay[PATH_MAX+1];
D_PRINTF(abspath);
if(pipe(pipefd) == -1) {
perror(MSG_ERR_PIPE);
return 0;
}
pid = fork();
if(pid == -1) {
perror(MSG_ERR_FORK);
return 0;
}
/******************** PARENT ********************/
if(pid > 0) {
/* if we read anything, our child succeded */
if( read(pipefd[0],&tmp,sizeof(tmp)) == -1) {
perror(MSG_ERR_IO);
return 0;
}
return pid; /* return watchers pid */
}
/****************** CHILD: Service watcher ********************/
sa.sa_handler = sig_terminate;
sigaction(SIGTERM,&sa,NULL); /* term = kill respawing process */
/* sigterm handler should kill first our watching pid, reset the
pid to 0 and then we'll kill ourselves */
tmp = 1;
if( write(pipefd[1],&tmp,sizeof(tmp)) == -1) {
perror(MSG_ERR_IO);
_exit(1);
}
/* try to read delay into sock */
strcpy(delay,abspath);
strcat(delay,SLASH);
strcat(delay,C_DELAY);
/* reuse sock to specify delay */
sock = -1;
tmp = open(delay,O_RDONLY);
if(tmp != -1) {
pipefd[0] = read(tmp,&delay[0],PATH_MAX);
if(pipefd[0] > 0 && pipefd[0] <= PATH_MAX) {
delay[pipefd[0]] = 0;
sock = atoi(delay);
}
close(tmp);
}
do {
/* exec_svc will set cpid accordingly */
if( ! exec_svc(abspath, CMD_START_SVC) ) {
if(cpid != 0) {
D_PRINTF("sloefen");
sleep(SLEEP_SVC);
D_PRINTF("Zuende geschlafen");
}
}
} while(cpid); /* cpid is reset by sig_terminate() */
/* FIXME: put most code of sig_terminate here, look for no_kill */
/* start off task */
exec_svc(abspath,CMD_STOP_SVC);
D_PRINTF("jetzt weg");
_exit(0);
}

View file

@ -0,0 +1,49 @@
/***********************************************************************
*
* 2005-2006 Nico Schottelius (nico-linux-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* run initial service(s)
*/
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include "cinit.h"
#include <time.h>
/***********************************************************************
* start the first service
*/
int run_init_svc(char *cinit_svc)
{
pid_t pid;
/* leave cinit alone */
pid = fork();
if(pid == -1) { /* err */
print_errno(MSG_ERR_FORK);
return 0;
} else if(pid == 0) { /* child */
cinit_ipc_sclose();
set_signals(ACT_CLIENT);
/* FIXME: open stderr, stdin, stdout to files / syslog / logable ?
* IMPLEMENT PER SERVICE!
*/
run_svc(cinit_svc);
_exit(0); /* nobody cares about us, so exit successfully anyway */
}
/* parent exits, we don't care about our children */
return 1;
}
/* ready for cinit-0.2 */

View file

@ -0,0 +1,45 @@
/***********************************************************************
*
* 2005-2006 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* run initial service(s)
*/
#include <unistd.h> /* _exit, fork */
#include "cinit.h"
#include "messages.h"
#include "ipc.h"
int run_svc(char *rpath) { rpath = "test"; return 0; } /* a hack to compile cinit for now */
int run_init_svc(char *cinit_svc)
{
pid_t pid;
/* leave cinit alone */
pid = fork();
if(pid == -1) { /* err */
print_errno(MSG_ERR_FORK);
return 0;
} else if(pid == 0) { /* child */
cinit_ipc_sclose();
set_signals(ACT_CLIENT);
if(!cinit_ipc_logon()) _exit(1);
/* FIXME: open stderr, stdin, stdout to files / syslog / logable ?
* IMPLEMENT PER SERVICE!
*/
run_svc(cinit_svc);
_exit(0); /* nobody cares about us, so exit successfully anyway */
}
/* parent exits, we don't care about our children */
return 1;
}
/* ready for cinit-0.2 */

View file

@ -0,0 +1,86 @@
/*
* cinit
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run services parallel
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include "cinit.h"
/***********************************************************************
* parallel run forked() run_svc()
*/
int run_run_svcs(char *abspath)
{
DIR *d_tmp = NULL;
struct dirent *tdirent;
char pathbuf[PATH_MAX+1];
pid_t pids[MAX_DEPS];
int status, i, ret = 1;
D_PRINTF(abspath);
d_tmp = opendir(abspath);
/* if there is no such dir, we are finished */
if(d_tmp == NULL) {
return 1;
}
i = 0;
while( (tdirent = readdir(d_tmp) ) != NULL) {
/* ignore . and .. and everything with a . at the beginning */
if ( *(tdirent->d_name) == '.') continue;
if(i < MAX_DEPS) {
pids[i] = fork();
} else {
LOG(MSG_ERR_DEPS);
break;
}
if(pids[i] == -1) { /* err */
perror(MSG_ERR_FORK);
return 0;
}
if(pids[i] == 0) { /* child */
strcpy(pathbuf,abspath);
strcat(pathbuf,SLASH);
strcat(pathbuf,tdirent->d_name);
if ( run_svc(pathbuf) )
_exit(0);
else
_exit(1);
} else { /* parent */
++i;
}
}
closedir(d_tmp);
/* wait for pids */
--i; /* the index is one too much since last i++ */
while(i >= 0) {
waitpid(pids[i], &status, 0);
/* if anything failed, we failed */
if( ! WIFEXITED(status)) {
ret = 0;
} else {
if( WEXITSTATUS(status) ) {
ret = 0;
}
}
--i;
}
return ret;
}

View file

@ -0,0 +1,131 @@
/*
* (c) 2005 Nico Schottelius (nico-cinit at schottelius.org)
* run_svc
* part of cinit
*/
/* headers are clean */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>
#include <time.h>
#include "cinit.h"
#error "needs to be cleaned up"
/***********************************************************************
* run_svc: run a service and before all dependencies
*/
int run_svc(char *rpath)
{
int tmp;
pid_t pid;
char abspath[PATH_MAX], pathtmp[PATH_MAX]; /* pathtmp will be misused */
struct stat buf;
struct timespec ts;
/******************* absolute PATH ***************/
/* save current working dir */
if(! (int) getcwd(pathtmp,PATH_MAX)) {
print_errno(pathtmp);
return RT_UNSPEC;
}
/* change to rpath */
if(chdir(rpath) == -1) {
print_errno(rpath);
return RT_NOTEXIST;
}
/* get absolute name of rpath */
if(! (int) getcwd(abspath,PATH_MAX)) {
perror(abspath);
return RT_UNSPEC;
}
/* change back */
if(chdir(pathtmp) == -1) {
perror(pathtmp);
return RT_UNSPEC;
}
D_PRINTF(abspath);
/******************* REGISTER SERVICE ***************/
do {
tmp = msg_svc_on_off(abspath,CMD_START_SVC); /* check status */
switch(tmp) {
case ST_FAIL: /* somebody failed before, we won't retry */
return RT_SVC_FAILED;
break;
case ST_TMP: /* someone is working on it */
ts.tv_sec = SLEEP_RERUN;
nanosleep(&ts,NULL);
break;
case ST_ONCE: /* somebody did our work */
case RT_ERR_COMM: /* communication failed */
case ST_RESPAWN: /* somebody does our work */
case ST_NEED_FAIL: /* the needs failed before */
return tmp;
break;
case RT_TMPNOW: /* do not go to default: */
break;
default:
mini_printf(MSG_SHOULD_NOT_HAPPEN,1);
return RT_UNSPEC;
break;
}
} while(tmp != RT_TMPNOW);
/******************* BEGIN DEPENDENCIES ***************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
strcat(pathtmp,C_NEEDS);
/* check for needs */
if( stat(pathtmp,&buf) == 0 ) {
if( ! run_run_svcs(pathtmp) ) {
SERVICE_LOG(abspath,LOG_NEED_FAIL);
msg_change_status(abspath, ST_NEED_FAIL, 0);
return ST_NEED_FAIL;
}
}
/********** WANTS ************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
strcat(pathtmp,C_WANTS);
if( stat(pathtmp,&buf) == 0 ) {
run_run_svcs(pathtmp); /* don't care about what happens with the want svc */
}
/******************* execute services ***************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
strcat(pathtmp,C_RESPAWN);
if( stat(pathtmp,&buf) == 0) {
pid = respawn_svc(abspath);
tmp = ST_RESPAWN;
} else {
pid = exec_svc(abspath, CMD_START_SVC);
tmp = ST_ONCE;
}
if(!pid) {
msg_change_status(abspath, ST_FAIL, pid);
return ST_FAIL;
}
if(!msg_change_status(abspath, tmp, pid) ) {
return RT_ERR_COMM;
}
return tmp; /* ST_ONCE || ST_RESPAWN */
}
/* cinit-0.2 return codes implemented */

View file

@ -0,0 +1,60 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* terminate: terminate our watching pid
* part of cinit
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include "cinit.h"
/* **********************************************************************
* terminate the watching service
*/
void sig_terminate(int signal)
{
struct timespec ts;
int status;
/* FIXME: only send SIGTERM, if not_kill does not exist */
if( kill(cpid,SIGTERM) == -1) {
if(errno != ESRCH) {
perror(MSG_TERMKILL);
}
}
/* variabel delay */
if(sock > 0) {
ts.tv_sec = sock;
} else {
ts.tv_sec = SLEEP_KILL_SVC; /* defined in conf/sleep_kill_svc */
}
/* if it still exists... */
if(kill(cpid,0) != -1) {
/* kill if there is a delay */
if(sock != 0) {
nanosleep(&ts,NULL);
status = kill(cpid,SIGKILL);
if( status == -1) {
if(errno != ESRCH) {
perror(MSG_TERMKILL);
}
}
}
}
/* remove zombie if killed, if delay is zero wait for it */
waitpid(cpid,&status,0);
/* reset the watching pid to zero (NOT THE WATCHER's!) */
cpid = 0;
D_PRINTF("muesste weg sein");
return;
}

View file

@ -0,0 +1,23 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* read data from cinit to the client
*/
#include "ipc.h" /* IPC */
/* gets a bunch of bytes and returns the answer from cinit */
int cinit_read_from(char **dest, int len)
{
if(!cinit_ipc_logon()) return NULL;
if(!cinit_ipc_connect()) return NULL;
/* FIXME: add length to ipc function? */
if(!cinit_ipc_csend(data)) return NULL;
return 1;
}

View file

@ -0,0 +1,159 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* cmd - the cinit client program - sends commands to cinit
*/
#include <unistd.h> /* getopt */
#include <signal.h> /* signals */
#include <stdio.h> /* printf() */
#include <stdlib.h> /* free() */
#include <string.h> /* strncmp */
#include <stdint.h> /* integers */
#include <limits.h> /* PATH_MAX */
#include "cmd.h" /* own header */
#include "signals.h" /* which signal */
#include "svc.h" /* service related */
#include "intern.h" /* print_errno() */
#include "cinit.h" /* cinit external */
#define C_USAGE(error) usage(USAGE_TEXT,error)
/***********************************************************************
* cmd: main
*/
int main(int argc, char **argv)
{
int opt, tmp, cnt;
int32_t status;
pid_t pid;
char *svc, *p = NULL;
char buf[PATH_MAX];
cnt = tmp = 0;
/*
* -d w(ants) excluded)
* -e n(eeds excluded)
* -d i(nclude everything)
*/
while((opt = getopt(argc,argv,CMD_OPTIONS)) != -1) {
++cnt;
switch(opt) {
/********************************************/
case 'h': /* help */
printf(CMD_USAGE);
return 0;
break;
case 'V': /* version */
printf("%s\n",CMD_VERSION);
return 0;
break;
/********************************************/
case 'e': /* enable service */
svc = optarg;
break;
case 'd': /* disable service */
svc = optarg;
break;
/********************************************/
case 'p': /* get pid */
case 's': /* get status */
svc = optarg;
/* relative path, add the cinit svc path in front of it */
/* FIXME: use buf! */
if(strncmp(svc,SLASH,strlen(SLASH))) {
p = malloc(strlen(CINIT_DIR)
+ strlen(SLASH)
+ strlen(SVCDIR)
+ strlen(SLASH)
+ strlen(svc)
+ 1);
if(!p) {
/* bad error */
return 2;
}
strcpy(p,CINIT_DIR);
strcat(p,SLASH);
strcat(p,SVCDIR);
strcat(p,SLASH);
strcat(p,svc);
svc = p;
}
if(opt == 's') {
status = cinit_get_svc_status(svc);
if(status < 0) {
printf("Communication error\n");
tmp = 1;
} else {
switch(status) {
case CINIT_MSG_SVC_UNKNOWN:
printf("Unknown service: %s\n",svc);
tmp = 1;
break;
case CINIT_MSG_OK:
printf("Status of %s is: %d\n",svc, status);
tmp = 0;
break;
/* should not happen */
default:
printf("Unknown status returned for %s: %d\n",svc, status);
tmp = 3;
break;
}
}
} else { /* -p */
pid = cinit_svc_get_pid(svc);
if(pid == 0) {
printf("Unknown service: %s\n",svc);
tmp = 1;
} else {
printf("PID of %s: %d\n",svc, pid);
tmp = 0;
}
}
if(p) free(p);
return tmp;
break;
case 'v': /* get version of cinit */
tmp = cinit_get_version(buf);
if(tmp) {
printf("Version of cinit: %s\n", buf);
return 0;
} else {
printf("Cannot get version of cinit!\n");
return 1;
}
break;
/* FIXME: add -V: version of cmd */
default:
printf("Unimplemented option :-)\n");
return 1;
break;
}
}
if(!cnt) {
printf(CMD_USAGE);
return 1;
}
return 0;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Halt the system through a kill call
*/
#include <signal.h> /* kill() */
#include "messages.h" /* MSG_* */
#include "intern.h" /* print_errno() */
#include "signals.h" /* signals mapping */
int main()
{
if(kill(1,SIG_CINIT_HALT) == -1) {
print_errno(MSG_HALT_KILL);
return 1;
}
return 0;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Reboot the system through a kill call
*/
#include <signal.h> /* kill() */
#include "messages.h" /* MSG_* */
#include "intern.h" /* print_errno() */
#include "signals.h" /* signals mapping */
int main()
{
if(kill(1,SIG_CINIT_POWEROFF) == -1) {
print_errno(MSG_POWEROFF_KILL);
return 1;
}
return 0;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Reboot the system through a kill call
*/
#include <signal.h> /* kill() */
#include "messages.h" /* MSG_* */
#include "intern.h" /* print_errno() */
#include "signals.h" /* signals mapping */
int main()
{
if(kill(1,SIG_CINIT_REBOOT) == -1) {
print_errno(MSG_REBOOT_KILL);
return 1;
}
return 0;
}

View file

@ -0,0 +1,20 @@
All abstracted communication functions. Do not depend on the underlying
inter process communication mechanism.
- send_command(): client function: sends a command to cinit
- send_service(): client function: send the service name to operate on
- read_command(): server function: reads beginning of a command
* Extracts the command
* reads client identification (=pid)
* calls other functions, depending on the command send => switch()
- read_service(): server function: reads service
- write_answer(): server function: answer?
* sends answers to clients => senseful?
TODO:
- define information function, that returns various information about
a service

View file

@ -0,0 +1,28 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* return pid of service
*
*/
#include <string.h> /* strncpy */
#include "svc-intern.h" /* VERSION */
#include "cinit.h" /* structure: cinit_answer */
int answer_svc_pid(char *svc, struct cinit_answer *asr)
{
struct listitem *tmp;
tmp = list_search(svc);
if(!tmp) {
asr->ret = CINIT_MSG_SVC_UNKNOWN;
} else {
asr->ret = CINIT_MSG_OK;
asr->options = tmp->pid;
}
return 1;
}

View file

@ -0,0 +1,28 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* return status of service
*
*/
#include <string.h> /* strncpy */
#include "svc-intern.h" /* VERSION */
#include "cinit.h" /* structure: cinit_answer */
int answer_svc_status(char *svc, struct cinit_answer *asr)
{
struct listitem *tmp;
tmp = list_search(svc);
if(!tmp) {
asr->ret = CINIT_MSG_SVC_UNKNOWN;
} else {
asr->ret = CINIT_MSG_OK;
asr->options = tmp->status;
}
return 1;
}

View file

@ -0,0 +1,21 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* return version of cinit
*
*/
#include <string.h> /* strncpy */
#include "config.h" /* VERSION */
#include "cinit.h" /* structure: cinit_answer */
int answer_version(struct cinit_answer *asr)
{
asr->ret = CINIT_MSG_OK;
strncpy(asr->data, VERSION, PATH_MAX);
return 1;
}

View file

@ -0,0 +1,36 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* cinit reads a command sent by a client, called by ipc listener
*
*/
#include "cinit.h" /* structures */
#include "intern.h" /* answer_svc_status() */
int read_command(struct cinit_question qsn, struct cinit_answer *asr)
{
switch(qsn.cmd) {
case CINIT_MSG_GET_VERSION:
if(!answer_version(asr)) return 0;
break;
case CINIT_MSG_GET_STATUS:
if(!answer_svc_status(qsn.data, asr)) return 0;
break;
case CINIT_MSG_GET_PID:
if(!answer_svc_pid(qsn.data, asr)) return 0;
break;
/* Unknown command: should not happen :-) */
default:
return 0;
break;
}
return 1;
}

View file

@ -0,0 +1,166 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Build **argv for execution in cinit way:
* 1. check whether cmd is a valid executable
* 2. try to read cmd.params and write parameters
* 3. try to read cmd.env and setup environment
*
* Returns:
* BA_OK: Everything went well, you can use the struct
* BA_NOTFOUND: Binary executable is not available
* BA_PARAMS: Reading the parameters failed (ignoring non-existence!)
* BA_ENV: Reading the environment failed (same as above)
* BA_OTHER: Other error
*/
#include <fcntl.h> /* open() */
#include <stdlib.h> /* *alloc() */
#include <unistd.h> /* readlink */
#include <errno.h> /* errno */
#include <limits.h> /* PATH_MAX */
#include <stdio.h> /* NULL */
#include <string.h> /* strchr */
#include <sys/stat.h> /* stat() */
#include "intern.h"
#include "build_argv.h"
/*
* char *basename: something we should execute
* (*basename) + ".params" will be added as parameters
* (*basename) + ".env" will be added as environment
*/
int cinit_build_argv(char *basename, struct ba_argv *bav)
{
int tmp;
int argc;
char pathtmp[PATH_MAX+1];
char *sbuf = NULL;
char *p;
/* sane values */
bav->argv = NULL;
bav->envp = NULL;
/***********************************************************************
* Try to get realname (for links)
*/
if((tmp = readlink(basename,pathtmp,PATH_MAX)) == -1) {
/* nothing there? */
if(errno == ENOENT) {
return BA_E_NOTFOUND;
}
if (errno != EINVAL) {
return BA_E_OTHER;
}
tmp=strlen(basename);
strncpy(pathtmp,basename,tmp);
}
pathtmp[tmp] = '\0';
++tmp; /* the byte to add to memory for \0;
neither readlink nor strlen count the \0 */
/***********************************************************************
* prepare argv0
*/
bav->argv = malloc(sizeof(char *));
if(bav->argv == NULL) return BA_E_MEM;
*bav->argv = malloc(tmp);
if(*(bav->argv) == NULL) return BA_E_MEM;
strncpy(*(bav->argv),pathtmp,tmp);
/********************** read params *********************/
/* FIXME check bounds! */
strcpy(pathtmp,basename);
strcat(pathtmp,C_PARAMS);
/* ORC_ERR_NONEXISTENT: Ok, have sbuf set to NULL
* ORC_OK: Ok, have a filled buffer (perhaps NULL, too)
* other: Error, print errno
*/
tmp = openreadclose(pathtmp,&sbuf);
if(tmp != ORC_ERR_NONEXISTENT && tmp != ORC_OK) {
print_errno(pathtmp);
return BA_E_PARAMS;
}
sbuf = strip_final_newline(sbuf);
/***********************************************************************
* Now split the string, converting \n to \0
*/
argc = 1; /* argv0 */
while(sbuf != NULL) {
p = strchr(sbuf,'\n');
bav->argv = realloc(bav->argv, sizeof(char *) * (argc + 1));
if(bav->argv == NULL) return BA_E_MEM;
bav->argv[argc] = sbuf; /* here begins the current argument */
if(p != NULL) { /* found another \n */
*p = '\0';
sbuf = p+1;
} else { /* end of string */
sbuf = NULL;
}
++argc;
}
/************ close argv list **************/
bav->argv = realloc(bav->argv, sizeof(char *) * (argc + 1));
if(bav->argv == NULL) return BA_E_MEM;
bav->argv[argc] = NULL; /* terminate argv list */
/********************** read environment *********************/
strcpy(pathtmp,basename);
strcat(pathtmp,C_ENV);
tmp = argc = 0;
sbuf = NULL;
tmp = openreadclose(pathtmp,&sbuf);
if(tmp != ORC_ERR_NONEXISTENT && tmp != ORC_OK) {
print_errno(pathtmp);
return BA_E_PARAMS;
}
sbuf = strip_final_newline(sbuf);
/************** build environment string **************/
argc = 0;
while(sbuf != NULL) {
p = strchr(sbuf,'\n');
bav->envp = realloc(bav->envp, sizeof(char *) * (argc + 1));
if(bav->envp == NULL) return BA_E_MEM;
bav->envp[argc] = sbuf;
/* if we found \n */
if(p != NULL) {
*p = '\0';
sbuf = p+1;
} else {
sbuf = NULL;
}
++argc;
}
/************ close env list **************/
bav->envp = realloc(bav->envp, sizeof(char *) * (argc + 1));
if(bav->envp == NULL) {
return BA_E_MEM;
}
bav->envp[argc] = NULL;
return BA_OK;
}

View file

@ -0,0 +1,112 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* The main file
*
*/
#include <unistd.h> /* getpid,chdir */
#include <string.h> /* str(ncmp,len,cpy,cat) */
#include <stdio.h> /* perror */
#include <stdlib.h> /* malloc */
#include "intern.h" /* general things */
#include "messages.h" /* messages */
#include "ipc.h" /* general ipc methods */
#include "svc-intern.h" /* gen_svc_tree */
struct listitem *svc_list = NULL;
struct dep *svc_init = NULL;
int svc_lock = 0; /* global svc-lock */
int main(int argc, char **argv)
{
char *initdir = CINIT_INIT; /* default init dir */
/* Is this really needed?
pid_t cpid;
if(cpid != 1) {
mini_printf(CINIT_VERSION,2);
mini_printf(MSG_USAGE,2);
return 0;
}*/
/* Look whether we should start a profile */
while(argc > 1) {
if(!strncmp(PROFILE, argv[argc-1], strlen(PROFILE) ) ) {
initdir = malloc(strlen(CINIT_SVCDIR) +
strlen(&argv[argc-1][strlen(PROFILE)]) + 2);
if(initdir == NULL) {
panic();
}
strcpy(initdir, CINIT_SVCDIR);
strcat(initdir, SLASH);
strcat(initdir, &argv[argc-1][strlen(PROFILE)]);
break;
}
--argc;
}
/* Bootup "logo" */
mini_printf(MSG_BOOTING,1); mini_printf(initdir,1); mini_printf("\n",1);
if(chdir(initdir) == -1) {
print_errno(initdir);
panic();
}
/* initialize ipc method */
if(!cinit_ipc_init()) {
panic();
}
/* listen to signals */
set_signals(ACT_SERV);
/* pre-calculate service tree */
if(!gen_svc_tree(initdir)) {
panic();
}
/* free, if we malloc()ed before */
if(strcmp(initdir,CINIT_INIT)) {
free(initdir);
}
/* change to /, so applications have that as cwd, too
* Is that really seneful? Does that help any application?
* If not, just for looking nice, that's not a reason to
* enable it.
if(chdir(SLASH) == -1) {
print_errno(SLASH);
panic();
} */
if(!tree_exec(svc_init)) {
panic();
}
while(1) {
cinit_ipc_listen();
/* check dependency list: perhaps we need to restart something */
/* implement in cinit-0.3pre14/5 */
// tree_exec(svc_init);
// reuse tree_exec()?
// if(dep) { svc_start() .. ?
}
/* OLD:
if(!cinit_ipc_listen()) {
panic();
} */
/* never reached */
return 0;
}

View file

@ -0,0 +1,97 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Communication defines
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "ipc.h"
/* cleaned up own headers */
#include "intern.h" /* set_signals */
#include "svc-intern.h" /* shutdown_services */
#include "messages.h" /* messages */
#include "reboot.h" /* cinit_poweroff&co */
/* cleaned headers */
#include <signal.h> /* kill() */
/***********************************************************************
* sig_reboot
* Shutdown the system
*/
void do_reboot(int signal)
{
//struct listitem *tmp;
//char **cmd;
//int i;
/*
* New code:
* 0. close user ipc
* - notify user!
* - do not allow user interupt anymore
* 1. shutdown services
* - notify user!
* 2. kill -TERM all processes
* - notify user!
* 3. kill -KILL all processes
* - notify user!
* 4. execute /etc/cinit/conf/{halt,reboot,poweroff}
* - notify user!
*/
/* do not listen to client requests anymore */
/* and tell the user what happens */
LOG(MSG_SHUTDOWN_START);
cinit_ipc_destroy();
set_signals(ACT_CLIENT); /* reset signal handlers */
/* shutdown all services: take care about the dependency tree */
LOG(MSG_SHUTDOWN_SVC);
shutdown_services(svc_list);
LOG(MSG_SHUTDOWN_KILL);
/* now: all services are down, let's kill all other processes */
if(kill(-1,SIGTERM) == -1) {
print_errno(MSG_TERMKILL);
}
sleep_before_kill();
if(kill(-1,SIGKILL) == -1) {
print_errno(MSG_KILLBILL);
}
/* Execute the last command */
LOG(MSG_SHUTDOWN_LAST);
execute_and_wait(CINIT_LAST);
/* do what we really wanted to do */
switch(signal) {
case SIGTERM: /* power off */
LOG(MSG_POWER_OFF);
cinit_poweroff();
break;
case SIGHUP: /* reboot */
LOG(MSG_REBOOT);
cinit_reboot();
break;
case SIGUSR1: /* halt */
LOG(MSG_HALT);
cinit_halt();
break;
}
/* FIXME: should we exit? */
_exit(0);
}

View file

@ -0,0 +1,34 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Execute something
*/
#include <unistd.h> /* execv */
#include "intern.h"
#include "messages.h"
void panic(void)
{
char *nargv[2];
if(execute_and_wait(CINIT_PANIC)) _exit(0);
/***********************************************************************
* THIS SHOULD NOT HAPPEN, fallback to hardcoded sulogin
* (conf/sulogin)
*/
nargv[0] = SULOGIN;
nargv[1] = NULL;
if(execv(SULOGIN,nargv) == -1) {
print_errno(MSG_FATAL_PANIC);
}
/* there's nothing todo, if everything fails */
_exit(23);
}

View file

@ -0,0 +1,40 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Define signal handlers
*/
#include <signal.h> /* sigaction, sigemtpyset */
#include <stdio.h> /* NULL */
#include "intern.h" /* defines */
#include "reboot.h" /* reboot related */
#include "signals.h" /* reboot related */
void set_signals(int action)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask); /* no other signals should be blocked */
sa.sa_flags = 0;
if(action == ACT_SERV) {
sa.sa_handler = sig_child;
sa.sa_flags = SA_NOCLDSTOP;
} else {
sa.sa_handler = SIG_DFL;
}
sigaction(SIGCHLD,&sa,NULL); /* what todo when a child exited */
sa.sa_flags = 0; /* reset flags */
if(action == ACT_SERV) {
sa.sa_handler = do_reboot;
}
sigaction(SIG_CINIT_HALT, &sa, NULL); /* halt */
sigaction(SIG_CINIT_POWEROFF, &sa, NULL); /* poweroff */
sigaction(SIG_CINIT_REBOOT, &sa, NULL); /* reboot */
}

View file

@ -0,0 +1,94 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* The child handler
*
*/
#include <sys/wait.h> /* waitpid */
#include <stdio.h> /* NULL */
#include <sys/time.h> /* gettimeofday() */ /* FIXME: CHECK POSIX */
#include <time.h> /* time(),gettime.. */ /* FIXME: CHECK POSIX */
#include "intern.h" /* mini_printf */
#include "svc-intern.h" /* list_search_pid */
#include "svc.h" /* list_search_pid */
#include "messages.h" /* messages/D_PRINTF */
extern int svc_lock;
/***********************************************************************
* sig_child: (c)collect the children
*/
void sig_child(int tmp)
{
/* New code:
* - search for pid in service list
* * if (respawn) -> start new
* - insert delay? if exit code is non-zero? if uptime too less?
* * if (once) -> update service status
* * else ignore, but reap away
*/
pid_t pid;
int delay;
struct listitem *svc;
/* wait until the lock is reset */
if(svc_lock) return;
// struct timeval now;
while((pid = waitpid(-1, &tmp, WNOHANG)) > 0) {
/* check if it's a watched child */
svc = list_search_pid((pid_t) pid);
if(svc != NULL) {
/* Check, that we are operating on it =. that it is no normal child */
/* Also check for ST_SH_* to catch race conditions, where
* status is not yet updated => does that make sense or is
* the status overwritten after we return out of here?
*/
printf("CHILD: %s (%ld) (%d) bekannt!\n",svc->abs_path, svc->status, pid);
if(svc->status & CINIT_ST_ONCE_RUN
|| svc->status & CINIT_ST_RESPAWNING) {
if(WIFEXITED(tmp) && !WEXITSTATUS(tmp)) {
svc_success(svc);
} else {
svc_fail(svc);
}
}
//mini_printf("WHILE: Vorm respawn!\n",1);
/* respawn: restart: FIXME Delay for regular dying services */
if(svc->status == CINIT_ST_RESPAWNING) {
svc_report_status(svc->abs_path,MSG_SVC_RESTART,NULL);
//delay = MAX_DELAY / (time(NULL) - svc->start);
/* if(gettimeofday(&now,NULL) == -1) {
print_errno(MSG_GETTIMEOFDAY);;
delay = 0;
} else {
delay = MAX_DELAY / (now.tv_sec - svc->start);
} */
delay = 5;
/* int test = time(NULL);
test++;
D_PRINTF("WHILE: IM respawn / for printf!\n");
printf("sig_child: %d, %d, %d, %d\n",
MAX_DELAY,
(int) time(NULL),
(int) svc->start,
(int) (test - svc->start)
); */
svc_start(svc,delay);
}
}
}
}

View file

@ -0,0 +1,45 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Execute something, but fork() before
*
*/
#include <sys/types.h> /* pid_t */
#include <sys/wait.h> /* waitpid */
#include <unistd.h> /* fork */
#include "messages.h" /* MSG_* */
#include "intern.h" /* print_errno, execute_sth */
int execute_and_wait(char *svc)
{
pid_t pid;
int status;
/* fork */
pid = fork();
if(pid == -1) {
print_errno(MSG_ERR_FORK);
return 0;
}
/* exec / child */
if(pid == 0) {
execute_sth(svc); /* exits itself */
}
/* wait / parent */
waitpid(pid,&status,0);
if(WIFEXITED(status)) {
if(WEXITSTATUS(status) == 0) {
return 1;
}
}
return 0;
}

View file

@ -0,0 +1,38 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Executes something: replaces us
*/
#include <unistd.h> /* _exit */
#include "intern.h"
#include "build_argv.h"
#include "messages.h" /* D_PRINTF */
void execute_sth(char *basename)
{
int tmp;
struct ba_argv bav;
tmp = cinit_build_argv(basename,&bav);
if((tmp = cinit_build_argv(basename,&bav)) != BA_OK) {
if(tmp != BA_E_MEM) { /* do not print something on memory errors */
print_errno(basename);
}
_exit(1);
}
/* tell the user what we execute */
mini_printf(MSG_INTRO_EXEC,1);
mini_printf((bav.argv)[0],1);
mini_printf("\n",1);
execve((bav.argv)[0], bav.argv, bav.envp);
print_errno(basename);
_exit(1); /* simply exit non-zero. That's enough for cinit to recognize
it as faulty */
}

View file

@ -0,0 +1,60 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* check whether file exists and is a file
*/
#include <errno.h> /* errno */
#include <sys/stat.h> /* stat */
#include <stdio.h> /* NULL */
#include "intern.h" /* print_errno() */
#include "svc-intern.h" /* svc_report_status() */
#include "messages.h" /* messages.. */
int file_exists(char *filename)
{
struct stat buf;
/* check:
* - is it a link? if so, is it broken? report!
* - is it non existent? -> return non-existent
* - is it existent, but not a regular file? report!
*/
if(lstat(filename,&buf) == -1) { /* lstat fails? */
if(errno == ENOENT) {
/* FIXME: remove later */
printf("%s is not existing! => ok, most likely\n",filename);
return FE_NOT;
} else {
mini_printf("anderer fehler.\n",1);
print_errno(filename);
return FE_ERR;
}
} else {
if(S_ISLNK(buf.st_mode)) { /* is a link */
/* check link destination */
if(stat(filename,&buf) == -1) { /* do real stat(): */
if(errno == ENOENT) {
svc_report_status(filename,MSG_BROKENLINK,NULL);
return FE_NOLINK;
} else {
/* FIXME: MSG_*, ?? */
mini_printf("anderer fehler.\n",1);
print_errno(filename);
return FE_ERR;
}
}
}
} /* caught all stat() errors */
if(!S_ISREG(buf.st_mode)) {
svc_report_status(filename,MSG_NONREGULAR,NULL);
return FE_OTHER;
}
return FE_FILE;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Print the world!
*
*/
#include <unistd.h>
void mini_printf(char *str,int fd)
{
char *p;
/* don't get fooled by bad pointers */
if(str == NULL) return;
p = str;
while(*p) p++;
write(fd,str,(size_t) (p - str));
}

View file

@ -0,0 +1,66 @@
/***********************************************************************
*
* 2006 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* read a file
*
*/
#include <unistd.h> /* open, read, close */
#include <string.h> /* strncpy */
#include <stdlib.h> /* realloc */
#include <errno.h> /* errno */
#include <stdio.h> /* NULL */
#include <fcntl.h> /* open */
#include "intern.h" /* ORC_* */
int openreadclose(char *filename, char **where)
{
int tmp;
int cnt;
int fd;
char buf[512];
*where = NULL;
/* what a wonderful loop */
while((fd = open(filename,O_RDONLY)) == -1) {
if(errno == ENOENT) return ORC_ERR_NONEXISTENT;
if(errno != EINTR) return ORC_ERR_OPEN;
}
cnt = 0;
while (1) {
tmp = read(fd,buf,512);
if(tmp == -1) {
if(errno == EINTR)
continue;
else
return ORC_ERR_READ;
} else if(tmp == 0) {
break;
}
cnt += tmp;
*where = realloc(*where,cnt + 1);
if(*where == NULL) return ORC_ERR_MEM;
/* FIXME check correctness of copied buffer...
* and get some sleep..soon, very soon! */
strncpy(&(*where)[cnt-tmp],buf,tmp);
}
while((fd = close(fd)) == -1) {
if(errno == EINTR) continue;
return ORC_ERR_CLOSE;
}
/* terminate string! */
(*where)[cnt] = '\0';
return ORC_OK;
}

View file

@ -0,0 +1,40 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* create an absulte path
*/
#include <unistd.h> /* chdir(),getcwd */
#include <limits.h> /* PATH_MAX */
#include "intern.h" /* print_errno */
#include "messages.h" /* messages */
int path_absolute(char *relpath, char *newpath, size_t size)
{
char oldpath[PATH_MAX+1];
if(!getcwd(oldpath,PATH_MAX+1)) {
print_errno(MSG_GETCWD);
return 0;
}
if(chdir(relpath) == -1) {
print_errno(relpath);
return 0;
}
if(!getcwd(newpath,size)) {
print_errno(relpath);
return 0;
}
if(chdir(oldpath) == -1) {
print_errno(oldpath);
return 0;
}
return 1;
}

View file

@ -0,0 +1,28 @@
/***********************************************************************
*
* 2006 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* create path to needs
*/
#include <string.h> /* strlen */
#include <limits.h> /* PATH_MAX */
#include "intern.h" /* mini_printf, PD_ERR */
int path_append(char *path, char *append)
{
size_t end = strlen(path);
if(strcmp(&path[end-1],SLASH)) {
if((end + strlen(SLASH) + strlen(append)) > PATH_MAX) return 0;
strcat(path,SLASH);
} else {
if((end + strlen(append)) > PATH_MAX) return 0;
}
strcat(path,append);
return 1;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* stolen from tcpserver_blocker
*
* Author: Nico Schottelius
* Date: 2006-08-24
*
* Print the error found in errno
*/
#include <string.h> /* strerror */
#include <errno.h> /* errno */
#include "intern.h" /* mini_printf, PD_ERR */
void print_errno(char *msg)
{
if(msg) {
mini_printf(msg, FD_ERR);
mini_printf(": ", FD_ERR);
}
mini_printf(strerror(errno), FD_ERR);
mini_printf("\n", FD_ERR);
}

View file

@ -0,0 +1,43 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Sleep:
* read configuration,
* fallback to builtin value if not possible,
* sleep.
*
*/
#include <time.h> /* nanosleep */
#include <stdlib.h> /* strtol() */
#include <errno.h> /* errno */
#include "intern.h" /* print_errno */
#include "messages.h" /* messages */
void sleep_before_kill()
{
char *content;
int tmp;
struct timespec ts;
if(openreadclose(CINIT_SLEEPFILE,&content) == ORC_OK) {
errno = 0;
tmp = strtol(content, NULL, 10);
if(errno != 0) tmp = SLEEP_KILL;
free(content);
} else {
mini_printf(MSG_BUILTIN_SLEEP,1);
tmp = SLEEP_KILL;
}
ts.tv_sec = tmp;
ts.tv_nsec = 0;
if(nanosleep(&ts,NULL) == -1) {
print_errno(MSG_ERR_SLEEP);
}
}

View file

@ -0,0 +1,33 @@
/***********************************************************************
*
* 2006 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* If the last character is \n, shrink the memory and remove it
*
*/
#include <stdio.h> /* NULL */
#include <string.h> /* strchr */
#include <stdlib.h> /* alloc */
char *strip_final_newline(char *str)
{
char *p;
/* don't get fooled by bad pointers */
if(str == NULL) {
return NULL;
}
p = strrchr(str,'\n');
if(p) {
if(*(p+1) == '\0') {
*p = '\0'; /* DO NOT FORGET TO TERMINATE STRING */
str = realloc(str,(p-str));
}
}
return str;
}

View file

@ -0,0 +1,21 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* usage: tell the world what we want - seriously no capitalism
* usage: tell the user what's wrong and a help text
*
*/
#include <unistd.h> /* _exit() */
#include "intern.h" /* mini_printf */
void usage(char *banner, char *text)
{
/* print banner + error message */
mini_printf(banner,1);
mini_printf(text,1);
_exit(1);
}

View file

@ -0,0 +1,38 @@
/***********************************************************************
*
* 2006 Nico Schottelius (nico-linux-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* build **argv
*/
#ifndef CINIT_BA_HEADER
#define CINIT_BA_HEADER
/*****************************************************************************
* Defines: return values
*/
enum {
BA_OK,
BA_E_NOTFOUND,
BA_E_PARAMS,
BA_E_ENV,
BA_E_MEM,
BA_E_OTHER
};
/*****************************************************************************
* Structures
*/
struct ba_argv {
char **argv;
char **envp;
};
/*****************************************************************************
* Functions
*/
int cinit_build_argv(char *basename, struct ba_argv *bav);
#endif

View file

@ -0,0 +1,66 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* Header file for external programs (in theory)
*/
#ifndef __CINIT_EXTERNAL_HEADER
#define __CINIT_EXTERNAL_HEADER
/* includes */
#include <stdint.h> /* required for functions */
#include <limits.h> /* PATH_MAX */
#include <sys/types.h> /* pid_t */
/*
* structures: independent of the ipc code!
*/
/* messages from the client */
struct cinit_question {
int32_t cmd;
char data[PATH_MAX];
int32_t options;
};
/* messages from cinit */
struct cinit_answer {
int32_t ret;
int32_t options;
char data[PATH_MAX];
};
/* codes for messages */
enum {
/* questions */
CINIT_MSG_QUESTIONS=1000, /* begin questions at 1000 */
CINIT_MSG_GET_STATUS, /* status of a service */
CINIT_MSG_GET_PID, /* get pid of a service */
CINIT_MSG_GET_VERSION, /* version of cinit */
/* answers */
CINIT_MSG_ANSWERS=2000, /* begin answers at 2000 */
CINIT_MSG_OK, /* general ok value */
CINIT_MSG_ERR, /* general error value */
CINIT_MSG_SVC_UNKNOWN /* Services is not known */
};
struct cinit_msg_msg {
int code;
char *msg;
};
//struct cinit_msg_msg cinit_codes2messages[] = {
//}
/* functions */
pid_t cinit_svc_get_pid(char *);
int32_t cinit_get_svc_status(char *);
int cinit_get_version(char *);
int cinit_send_to(struct cinit_question *, struct cinit_answer *);
#endif

View file

@ -0,0 +1,40 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* Header file for the cmd (cinit management)
*/
#ifndef CINIT_CMD_HEADER
#define CINIT_CMD_HEADER
#define CMD_USAGE "cmd - cinit management\n\n" \
"cmd -[ed] -[nw] -[ps] [service] -[v]\n\n" \
" -e: enable service\n" \
" including dependencies\n" \
" -d: disable service\n" \
" including dependencies\n\n" \
" -n: without needs\n" \
" Skip wants when en/disabling\n" \
" -w: without wants\n" \
" Skip needs when en/disabling\n\n" \
" -h: get help\n" \
" this messages" \
" -p: get process id (pid)\n" \
" of specified service\n" \
" -s: get status\n" \
" of specified service\n" \
" -v: get version\n" \
" of cinit\n" \
" -V: get version\n" \
" of cmd\n" \
""
#define CMD_OPTIONS "e:d:hp:s:vV"
#define MSG_KILL "kill()"
#define CMD_VERSION "cmd 0.1"
#endif

View file

@ -0,0 +1,114 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* internal header
*/
#ifndef _CINIT_INTERN_H
#define _CINIT_INTERN_H
/* includes */
#include <sys/types.h> /* pid_t */
#include "config.h" /* paths, socket options, etc. */
#include "cinit.h" /* structures: answer / question */
/***********************************************************************
* Defines
*/
#define SLASH "/"
#define CINIT_CONFDIR CINIT_DIR SLASH C_CONFDIR
#define CINIT_PANIC CINIT_CONFDIR SLASH C_PANIC
enum { /* FIXME: there are some default defines somewhere for that */
FD_IN=0,
FD_OUT=1,
FD_ERR=2
};
enum { /* returns of openreadclose */
ORC_OK, /* everything went fine */
ORC_ERR_NONEXISTENT, /* file does not exist */
ORC_ERR_OPEN, /* error opening the file */
ORC_ERR_READ,
ORC_ERR_CLOSE,
ORC_ERR_MEM
};
/* values for execute_sth:
* STRICT: print and error, if .../on does not exist
* NOSTRICT: no .../on is fine
*/
enum {
EXEC_STRICT,
EXEC_NOSTRICT
};
enum {
FE_FILE, /* file exists and is a file */
FE_OTHER, /* file exists, but is no file */
FE_NOT, /* file does not exist */
FE_NOLINK, /* file is a broken symbolic link*/
FE_ERR /* some error occured */
};
/***********************************************************************
* Paths
*/
#define CINIT_SVCDIR CINIT_DIR SLASH SVCDIR
#define CINIT_INIT CINIT_SVCDIR SLASH C_INIT
#define CINIT_TMNT CINIT_DIR SLASH C_TMP
#define CINIT_SOCK CINIT_TMNT SLASH C_SOCK
#define CINIT_BIN PREFIX SLASH "sbin" SLASH "cinit"
#define CINIT_CONFDIR CINIT_DIR SLASH C_CONFDIR
#define CINIT_PANIC CINIT_CONFDIR SLASH C_PANIC
#define CINIT_LAST CINIT_CONFDIR SLASH C_LAST
#define CINIT_SLEEPFILE CINIT_CONFDIR SLASH SLEEP_BEFORE_KILL
/* needed by set_signals */
#define ACT_SERV 0
#define ACT_CLIENT 1
/* functions (used by server and client) */
void mini_printf(char *str, int fd);
void set_signals(int action);
//void usage(char *banner, char *stext);
/* core functions */
void panic(void);
void sig_child(int signal);
/* client / message functions */
//int msg_svc_on_off(char *svc, char action);
//int msg_change_status(char *svc, char status, pid_t pid);
//int begin_msg(char cmd);
/* client functions */
pid_t respawn_svc(char *abspath);
char **read_file(char *file);
void sig_terminate(int signal);
/* communication */
int read_command(struct cinit_question, struct cinit_answer *);
int answer_svc_status(char *, struct cinit_answer *);
int answer_svc_pid(char *, struct cinit_answer *);
int answer_version(struct cinit_answer *);
/* generic */
void execute_sth(char *basename);
int execute_and_wait(char *svc);
int path_append(char *path, char *append);
int path_absolute(char *relpath, char *buf, size_t size);
int openreadclose(char *filename, char **where);
char *strip_final_newline(char *str);
int file_exists(char *filename);
void sleep_before_kill();
/* util */
void print_errno(char *text);
#endif /* INTERN */

View file

@ -0,0 +1,41 @@
/***********************************************************************
*
* 2006 Nico Schottelius (nico-linux-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* Prototypes for ipc handler
*/
#ifndef CINIT_IPC_HEADER
#define CINIT_IPC_HEADER
/* FIXME: change to cinit/types.h later */
#include "cinit.h"
/*****************************************************************************
* Functions: in server
*/
int cinit_ipc_init(void); /* init in init */
int cinit_ipc_listen(void); /* listen in init */
int cinit_ipc_sclose(void); /* fork of cinit come from outside! */
int cinit_ipc_ssend(void *data); /* send to a client from the server */
void cinit_ipc_destroy(void); /* destroy ipc handler in cinit */
/*****************************************************************************
* Functions: in clients
*/
int cinit_ipc_logon(void); /* logon to init */
int cinit_ipc_connect(void); /* connect to init */
int cinit_ipc_csend(struct cinit_question *); /* ask the server */
int cinit_ipc_cread(struct cinit_answer *); /* read answer */
int cinit_ipc_logoff(void); /* logoff */
/*****************************************************************************
* Functions: shared
*/
#endif

View file

@ -0,0 +1,8 @@
include/intern.h
include/config.h
include/ipc.h
include/messages.h
include/os.h
include/reboot.h
include/signals.h
include/svc.h

View file

@ -0,0 +1,154 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit (at) schottelius.org)
*
* part of cLinux/cinit
*
* All messages
*/
#ifndef _CINIT_MSG_H
#define _CINIT_MSG_H
/* version */
#define CINIT_VERSION "cinit-" VERSION
#define MSG_BOOTING CINIT_VERSION ": Booting from "
#define MSG_DP ": "
#define MSG_USAGE_1 ": fast executing, small and simple init "
#define MSG_USAGE_2 "with support for profiles\n"
#define MSG_USAGE_3 "\nError: cinit must be started as PID 1.\n"
#define MSG_USAGE MSG_USAGE_1 MSG_USAGE_2 MSG_USAGE_3
#define MSG_ERR_FORK "fork"
#define MSG_ERR_IO "i/o"
#define MSG_ERR_OPEN "open"
#define MSG_ERR_PIPE "pipe"
#define MSG_ERR_READ "read"
#define MSG_ERR_EXECVE "execve"
#define MSG_ERR_ALLOC "memory allocation"
#define MSG_ERR_UMOUNT "umount"
#define MSG_ERR_MOUNT "mount"
#define MSG_NOT_DIR "not a directory"
#define MSG_CHDIR "chdir"
#define MSG_READLINK "readlink"
#define MSG_ERR_ADD_SVC "Adding service failed"
#define MSG_CMD_UNKNOWN "Unknown command"
//#define MSG_ERR_DEPS "Too many dependencies"
//#define MSG_ERR_ACCEPT "accept"
//#define MSG_ERR_WAITPID "waitpid"
//#define MSG_ERR_POLL "poll"
//#define MSG_ERR_MODIFY "modify list failed"
//#define MSG_ERR_COMM "Communication failed"
//#define MSG_ERR_LESS_ARGS "Too less arguments!"
//#define MSG_ERR_BAD_ARGS "Wrong arguments / parameter"
//#define MSG_ERR_ARGS_LEN "Wrong parameter length"
#define LOG_SVC_STOPED "Service stoped"
#define LOG_SVC_ONCE "Started once"
#define LOG_SVC_RESPAWN "Respawns now"
//#define LOG_NEED_FAIL "One or more need failed"
//#define LOG_SVC_FAILED "Service already failed, not starting."
#define LOG_SVC_NOTEXIST "Service does not exist"
#define MSG_EXEC_FAILED "Failed to execute "
#define MSG_RESCUE "Switching to rescue mode ..."
#define MSG_UPDATE "Updating cinit ..."
#define MSG_HOT_REBOOT "Hot reboot in progress ..."
#define MSG_SHOULD_NOT_HAPPEN "This should not happen, I do not know what todo!"
/* DEBUG */
#ifdef DEBUG
# include <stdio.h>
# define D_PRINTF(x) ( printf("[%s:%d]: %s\n",__FILE__,__LINE__,x) )
#else
# define D_PRINTF(x) if(0) {}
#endif
/* macros */
#define SERVICE_LOG(svc,message) { \
mini_printf(svc,1); \
mini_printf(MSG_DP,1); \
mini_printf(message,1); \
mini_printf("\n",1); \
}
#define LOG(s) { \
mini_printf(s,1); \
mini_printf("\n",1); \
}
#define P_START_SERVICE(name) { mini_printf(MSG_START_SVC,1); mini_printf(name,1); mini_printf("\n",1); }
#define P_EXEC_FAILED(name) { mini_printf(MSG_EXEC_FAILED,1); mini_printf(name,1); mini_printf("\n",1); }
/* NEW (clean) Service status: Messages to the outside */
/* services: how they should be printed
* /etc/cinit/svc/long/name: started once
* /etc/cinit/svc/long/name: is respawning
* /etc/cinit/svc/long/name: FAILED (why it happened)
*/
#define MSG_INTRO_CINIT "cinit:"
#define MSG_INTRO_SPACE MSG_INTRO_CINIT " "
#define MSG_INTRO_SVC MSG_INTRO_CINIT
#define MSG_INTRO_STOP MSG_INTRO_CINIT "stop: "
#define MSG_INTRO_EXEC MSG_INTRO_CINIT "exec: "
/* FIXME: remove/append, but no intro! */
#define MSG_INTRO_FAIL "FAILED "
#define MSG_INTRO_RESPAWN MSG_INTRO_CINIT "respawn: "
#define MSG_INTRO_OK MSG_INTRO_CINIT "ok: "
#define MSG_SVC_FORK "fork() failed"
#define MSG_SVC_NEED_FAIL MSG_INTRO_FAIL "Needs failed for service"
#define MSG_SVC_FAIL MSG_INTRO_FAIL "Service failed!"
#define MSG_BUILTIN_SLEEP MSG_INTRO_STOP "Using built-in sleep"
#define MSG_TREE_EXEC MSG_INTRO_SPACE "Execution of reverse service tree\n"
/* general errors */
#define MSG_GETCWD "Getcwd failed! Your system is most likely broken!"
#define MSG_FATAL_PANIC MSG_INTRO_SPACE "I tried everything, but even panic() failed: "
#define MSG_ERR_SLEEP MSG_INTRO_SPACE "Sleep did not succeed"
#define MSG_GETTIMEOFDAY MSG_INTRO_SPACE "gettimeofday() failed!"
/* execution */
//#define MSG_EXECUTING MSG_INTRO_EXEC
/* stat() errors */
#define MSG_NONREGULAR "Is not a regular file."
#define MSG_BROKENLINK "Is a broken link."
/* Service messages */
#define MSG_SVC_START "Starting... "
#define MSG_SVC_STOP "Stoping... "
#define MSG_SVC_RESTART "Restarted."
#define MSG_SVC_SLEEP "Sleeping before restart"
#define MSG_SVC_OK_ONCE "Started once."
#define MSG_SVC_OK_RESPAWN "Is respawning."
/* Status messages */
#define MSG_SHUTDOWN_START MSG_INTRO_STOP "\nBeginning the shutdown process..."
#define MSG_SHUTDOWN_SVC MSG_INTRO_STOP "Shutting down services now..."
#define MSG_SHUTDOWN_KILL MSG_INTRO_STOP "Killing remaining processes..."
#define MSG_SHUTDOWN_LAST MSG_INTRO_STOP "Executing final service..."
#define MSG_POWER_OFF MSG_INTRO_STOP "Powering off..."
#define MSG_HALT MSG_INTRO_STOP "Halting system ..."
#define MSG_REBOOT MSG_INTRO_STOP "Rebooting ..."
/* client messages */
#define MSG_HALT_KILL "halt.kill"
#define MSG_REBOOT_KILL "reboot.kill"
#define MSG_POWEROFF_KILL "poweroff.kill"
/* reboot */
#define MSG_TERMKILL MSG_INTRO_FAIL "SIGTERM"
#define MSG_KILLBILL MSG_INTRO_FAIL "SIGKILL"
#endif /* _CINIT_MSG_H */

View file

@ -0,0 +1,20 @@
/***********************************************************************
*
* 2006 Nico Schottelius (nico-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* os specific functions
*/
#ifndef CINIT_OS_HEADER
#define CINIT_OS_HEADER
/*****************************************************************************
* Functions
*/
void cinit_halt(void);
void cinit_poweroff(void);
void cinit_reboot(void);
#endif

View file

@ -0,0 +1,35 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* reboot specific functions
*
*/
#ifndef CINIT_REBOOT_HEADER
#define CINIT_REBOOT_HEADER
/*****************************************************************************
* the main reboot function
*/
void do_reboot(int signal);
/*****************************************************************************
* os specific functions
*/
void cinit_reboot(void);
void cinit_halt(void);
void cinit_poweroff(void);
/*****************************************************************************
* Functions: abstract do_reboot
*/
#define cinit_do_reboot() do_reboot(SIGHUP)
#define cinit_do_halt() do_reboot(SIGUSR1)
#define cinit_do_poweroff() do_reboot(SIGTERM)
#endif

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* Define signals to use: needs signal.h to be included before.
*/
#ifndef CINIT_SIGNALS_HEADER
#define CINIT_SIGNALS_HEADER
#define SIG_CINIT_HALT SIGUSR1
#define SIG_CINIT_POWEROFF SIGTERM
#define SIG_CINIT_REBOOT SIGHUP
#endif

View file

@ -0,0 +1,82 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Internal service specifics
*/
#ifndef __CINIT_SVC_INTERN_H
#define __CINIT_SVC_INTERN_H
/* includes */
#include <sys/types.h> /* pid_t */
#include "config.h" /* paths, socket options, etc. */
/* service list */
struct listitem {
struct listitem *prev; /* previous item */
struct listitem *next; /* next item */
char *abs_path; /* name of service */
long int status; /* current status */
pid_t pid; /* pid of service / respawn watcher */
time_t start; /* time the process was started last time */
struct dep *wanted; /* list of services that want this service */
struct dep *needed; /* list of services that need this service */
struct dep *wants; /* list of services that this service wants */
struct dep *needs; /* list of services that this service needs */
};
/* list of dependencies */
struct dep {
struct dep *prev;
struct dep *next;
struct listitem *svc;
};
/* variables */
extern struct dep *svc_init; /* the services to start */
extern struct listitem *svc_list; /* the list of services */
/* list functions */
struct listitem *list_insert(char *path, int status);
int list_delete(char *path);
int list_modify(char *path, int new_status, pid_t new_pid);
struct listitem *list_search(char *path);
struct listitem *list_search_pid(pid_t pid);
/* service */
struct listitem *svc_create(char *svc);
struct listitem *gen_svc_tree(char *svc);
int check_add_deps(struct listitem *svc, int type);
void dep_entry_add(struct dep **list, struct dep *new);
struct dep *dep_entry_del(struct dep *del);
int tree_exec(struct dep *start);
int svc_set_status(struct listitem *li, int status);
int svc_should_respawn(struct listitem *li);
int svc_needs_status(struct listitem *li);
int dep_needs_wants_add(struct dep **list, struct listitem *svc, int type);
struct dep *dep_create(struct listitem *svc);
void svc_success(struct listitem *li);
void svc_fail(struct listitem *li);
void svc_report_status(char *svc, char *msg, char *err);
void svc_start(struct listitem *li, int delay);
void shutdown_services(struct listitem *start);
/***********************************************************************
* to decide whether to operate on needs or wants
*/
enum dep_types {
DEP_WANTS,
DEP_NEEDS
};
#endif /* _CINIT_SVC_INTERN_H */

View file

@ -0,0 +1,34 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Service status messages
*/
#ifndef __CINIT_SVC_MESSAGES_H
#define __CINIT_SVC_MESSAGES_H
#include "svc.h"
struct cinit_svc_msg {
int code;
char *msg;
};
struct cinit_svc_msg cinit_svc_msg_codes[] = {
{ CINIT_ST_SH_ONCE, "Service should be started once" },
{ CINIT_ST_SH_RESPAWN, "Service should respawn" },
{ CINIT_ST_ONCE_OK, "Service successfully started once" },
{ CINIT_ST_ONCE_FAIL, "Service failed to start once" },
{ CINIT_ST_RESPAWNING, "Service is respawning" },
{ CINIT_ST_NEED_FAILD, "One ore more needs failed" },
{ CINIT_ST_IN_LIST, "Service is in starter list" },
{ CINIT_ST_BAD_ERR, "Some strange error happened" },
{ CINIT_ST_ONCE_RUN, "Service is currently running once" },
{ CINIT_ST_NOT_EXIST, "This service does not exist" }
};
#endif /* _CINIT_SVC_H */

View file

@ -0,0 +1,40 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Service status (also exposed to the outside)
*/
#ifndef __CINIT_SVC_H
#define __CINIT_SVC_H
/***********************************************************************
* The real status types a service may have (ignore above)
* We have 32 Bits, we should use them ;-)
*/
enum cinit_svc_status {
/* first define basics */
CINIT_ST_SH_ONCE = 0x1, /* service SHould be started once */
CINIT_ST_SH_RESPAWN = 0x2, /* service SHould respawn */
CINIT_ST_ONCE_OK = 0x4, /* service was successfully started once */
CINIT_ST_ONCE_FAIL = 0x8, /* service failed to start */
CINIT_ST_RESPAWNING = 0x10, /* service is respawning */
CINIT_ST_NEED_FAILD = 0x20, /* this service is not started, need failed */
CINIT_ST_IN_LIST = 0x40, /* this service is being started (= in list) */
CINIT_ST_BAD_ERR = 0x80, /* some kind of error that SHOULD NOT happen */
CINIT_ST_ONCE_RUN = 0x100, /* the once process is currently running */
CINIT_ST_NOT_EXIST = 0x200 /* there's no such service in our database */
};
/***********************************************************************
* Possibilities the needs of a service may have
*/
enum cinit_svc_needs_status {
CINIT_SNS_NEEDS_STARTED = 1, /* all needs are started. We may start, too */
CINIT_SNS_NEEDS_FAILED, /* one ore more needs failed */
CINIT_SNS_NEEDS_UNFINISHED /* one ore more needs are not yet started */
};
#endif /* _CINIT_SVC_H */

View file

@ -0,0 +1,2 @@
This implementation uses the new realtime inferface of
posix instead of the old one functions.

View file

@ -0,0 +1,21 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Create new queues: One for recieving, one for sending
*
*/
#include <mqueue.h>
#include "cinit.h"
#include "config.h"
#include "msgq-rt.h"
int cinit_ipc_init(void)
{
return 1;
}

View file

@ -0,0 +1,20 @@
#include <mqueue.h>
#include <stdio.h>
int main()
{
mqd_t readq = mq_open("/test",O_RDWR|O_CREAT|O_EXCL);
//mqd_t readq = mq_open("/bin/ls",O_RDWR|O_CREAT|O_EXCL);
if(readq == -1) {
perror("oh nein");
return 1;
}
mqd_t writeq = mq_open("/bin/cp",O_WRONLY|O_CREAT|O_EXCL);
if(readq == -1) {
perror("oh oh nein");
return 1;
}
}

View file

@ -0,0 +1,39 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Create new queues: One for recieving, one for sending
*
*/
#ifndef CINIT_IPC_HEADER
#define CINIT_IPC_HEADER
#define MSGQ_PATHNAME "/cinit" /* identifier */
/***********************************************************************
* structures
*/
/* messages _from_ the client _to_ the server */
struct msgq_client {
long mtype;
pid_t pid;
struct msg_client msg;
};
/* messages _from_ the server _to_ the client */
struct msgq_server_short {
long mtype;
struct asw_sstatus answer;
};
/***********************************************************************
* Messages
*/
#define MSG_MSGQ_DESTROY "msgq-destroy"
#endif

View file

@ -0,0 +1,20 @@
cinit/src/ipc/msgq: About this msqg implementation
===================================================
Nico Schottelius <nico-linux-cinit__@__schottelius.org>
0.1, Initial Version from 2006-08-04
:Author Initials: NS
Intro here
Introduction
------------
cinit opens a
Files
-----
- README.text: This file
- cinit_init_ipc.c: Init
msgq.h
objects

View file

@ -0,0 +1,28 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Client reads messages from cinit
*
*/
#include <sys/msg.h> /* msg* */
#include <string.h> /* memcpy() */
#include <unistd.h> /* getpid() */
#include "intern.h" /* print_errno */
#include "msgq.h" /* msq specific */
int cinit_ipc_cread(struct cinit_answer *buf)
{
struct msgq_server asr;
if(msgrcv(__cinit_mq_in, &asr, sizeof(asr.asr), getpid(), 0) == -1) {
print_errno(MSG_MSGQ_MSGRCV);
return 0;
}
memcpy(buf, &(asr.asr), sizeof(*buf));
return 1;
}

View file

@ -0,0 +1,31 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Client sends messages to cinit
*
*/
#include <sys/msg.h> /* msgget */
#include <string.h> /* memcpy() */
#include "intern.h" /* print_errno */
#include "msgq.h" /* structure */
int cinit_ipc_csend(struct cinit_question *qsn)
{
struct msgq_client msg;
msg.mtype = 1; /* cinit = 1 */
/* copy question structure into the msgq-structure */
memcpy(&(msg.qsn), qsn, sizeof(msg.qsn));
if(msgsnd(__cinit_mq_out, &msg, sizeof(msg.qsn), 0) == -1) {
print_errno(MSG_MSGQ_MSGSEND);
return 0;
}
return 1;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Destory ipc mechanism, cinit is gonna die soon.
*
*/
#include <sys/msg.h> /* msgget */
#include <stdio.h> /* NULL */
#include "msgq.h" /* mq_in, mq_out */
#include "intern.h" /* print_errno */
void cinit_ipc_destroy(void)
{
if(msgctl(__cinit_mq_in, IPC_RMID, NULL) == -1) {
print_errno(__CINIT_MSG_MSGQ_DESTROY); /* print warning, continue */
}
if(msgctl(__cinit_mq_out, IPC_RMID, NULL) == -1) {
print_errno(__CINIT_MSG_MSGQ_DESTROY); /* print warning, continue */
}
}

View file

@ -0,0 +1,44 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Create new queues: One for recieving, one for sending
*
*/
#include <sys/ipc.h> /* ftok */
#include <sys/msg.h> /* msgget */
#include "intern.h" /* print_errno */
#include "msgq.h" /* message queue */
int cinit_ipc_init(void)
{
key_t k_tmp;
/* to_server */
k_tmp = ftok(__CINIT_MSGQ_PATHNAME, __CINIT_MSGQ_TO_SERVER);
if(k_tmp == -1) {
print_errno(__CINIT_MSG_MSGQ_FTOK);
return 0;
}
__cinit_mq_in = msgget(k_tmp, __CINIT_MSGQ_PERMS | IPC_CREAT);
if(__cinit_mq_in == -1) {
print_errno(__CINIT_MSG_MSGQ_MSGGET);
return 0;
}
k_tmp = ftok(__CINIT_MSGQ_PATHNAME, __CINIT_MSGQ_TO_CLIENT);
if(k_tmp == -1) {
print_errno(__CINIT_MSG_MSGQ_FTOK);
return 0;
}
__cinit_mq_out = msgget(k_tmp, __CINIT_MSGQ_PERMS | IPC_CREAT);
if(__cinit_mq_out == -1) {
print_errno(__CINIT_MSG_MSGQ_MSGGET);
return 0;
}
return 1;
}

View file

@ -0,0 +1,63 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Listen to messages
*
*/
#include <stdio.h> /* printf() */
#include <sys/msg.h> /* msgget */
#include <errno.h> /* errno */
#include "intern.h" /* print_errno */
#include "msgq.h" /* structs */
int cinit_ipc_listen(void)
{
int tmp;
struct cinit_msgq_client qsn;
struct cinit_msgq_server asr;
struct msqid_ds msq;
/* FIXME: remove debug */
printf("MSGQ-IPC: Listening...\n");
tmp = msgrcv(__cinit_mq_in, &qsn, sizeof (qsn.qsn), 0, 0);
/* message system problem */
if(tmp == -1) {
if(errno != EINTR) {
print_errno(__CINIT_MSG_MSGQ_MSGRCV);
}
return -1;
}
/* retrieve pid */
if(msgctl(__cinit_mq_in, IPC_STAT, &msq) == -1) {
print_errno(__CINIT_MSG_MSGQ_MSGCTL);
return -1;
}
// debug code
//printf("pid direkt: self: %d (peer: %d)\n",msq.msg_lrpid, msq.msg_lspid);
if(!read_command(qsn.qsn, &(asr.asr))) {
/* FIXME: mini_print */
printf("read command failed\n");
asr.asr.ret = CINIT_MSG_ERR;
}
asr.mtype = msq.msg_lspid;
if(msgsnd(__cinit_mq_out, &asr, sizeof(asr.asr), 0) == -1) {
/* FIXME: do different things on differen errnos ... */
print_errno("msgsend/answer");
}
return 1;
}

View file

@ -0,0 +1,14 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Disconnect from cinit
*
*/
int cinit_ipc_logoff(void)
{
return 1;
}

View file

@ -0,0 +1,44 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit schottelius.org)
*
* part of cLinux/cinit
*
* Listen to messages
*
*/
#include <sys/ipc.h> /* ftok */
#include <sys/msg.h> /* msgget */
#include "intern.h" /* print_errno */
#include "msgq.h" /* msgq constants */
int cinit_ipc_logon(void)
{
key_t k_tmp;
/* generiere nen schluessel: andersrum als im Server */
k_tmp = ftok(__CINIT_MSGQ_PATHNAME, __CINIT_MSGQ_TO_CLIENT);
if(k_tmp == -1) {
print_errno(__CINIT_MSG_MSGQ_FTOK);
return 0;
}
__cinit_mq_in = msgget(k_tmp, 0);
if(__cinit_mq_in == -1) {
print_errno(__CINIT_MSG_MSGQ_MSGGET);
return 0;
}
k_tmp = ftok(__CINIT_MSGQ_PATHNAME, __CINIT_MSGQ_TO_SERVER);
if(k_tmp == -1) {
print_errno(__CINIT_MSG_MSGQ_FTOK);
return 0;
}
__cinit_mq_out = msgget(k_tmp, 0);
if(__cinit_mq_out == -1) {
print_errno(__CINIT_MSG_MSGQ_MSGGET);
return 0;
}
return 1;
}

View file

@ -0,0 +1,58 @@
/***********************************************************************
*
* 2006-2007 Nico Schottelius (nico-cinit //@\\ schottelius.org)
*
* part of cLinux/cinit
*
* header of message queuing interface
*
*/
#ifndef __CINIT_IPC_HEADER
#define __CINIT_IPC_HEADER
#include <cinit.h> /* structures */
/***********************************************************************
* configuration
*/
#define __CINIT_MSGQ_PATHNAME "/bin/sh" /* should be on every *nix */
#define __CINIT_MSGQ_TO_SERVER 'i' /* also for ftok */
#define __CINIT_MSGQ_TO_CLIENT 'o' /* also for ftok */
#define __CINIT_MSGQ_PERMS 0660 /* queue permissions */
/***********************************************************************
* global variables: FIXME: rename, we're in client namespace!
*/
int __cinit_mq_in; /* input */
int __cinit_mq_out; /* output */
/***********************************************************************
* structures
*/
/* messages _from_ the client _to_ the server */
struct cinit_msgq_client {
long mtype;
struct cinit_question qsn;
};
/* messages _from_ the server _to_ the client */
struct cinit_msgq_server {
long mtype;
struct cinit_answer asr;
};
/***********************************************************************
* Messages
*/
#define __CINIT_MSG_MSGQ_FTOK "ftok"
#define __CINIT_MSG_MSGQ_MSGGET "msgget"
#define __CINIT_MSG_MSGQ_MSGCTL "msgctl"
#define __CINIT_MSG_MSGQ_MSGSEND "msgsend"
#define __CINIT_MSG_MSGQ_MSGRCV "msgrcv"
#define __CINIT_MSG_MSGQ_DESTROY "msgq-destroy"
#endif

View file

@ -0,0 +1,5 @@
ipc/current/cinit_ipc_init.o
ipc/current/cinit_ipc_listen.o
ipc/current/cinit_ipc_sclose.o
ipc/current/cinit_ipc_destroy.o
ipc/current/cinit_ipc_logon.o

View file

@ -0,0 +1,24 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* tell cinit that I want to start a service
* part of cinit
*/
#include <unistd.h>
#include <stdio.h>
#include "cinit.h"
int begin_msg(char cmd)
{
sock = connect_sock(sock);
if( sock == -1 ) {
return 0;
}
if(write(sock,&cmd,sizeof(cmd)) == -1) {
perror(MSG_ERR_IO);
return 0;
}
return 1;
}

View file

@ -0,0 +1,125 @@
/*
* (c) 2005, 2006 Nico Schottelius (nico-linux at schottelius.org)
* cinit.c
* part of cLinux/cinit
*/
/* *stat() */
#include <sys/stat.h>
#include <unistd.h>
/* open */
#include <fcntl.h>
/* siggnal */
#include <signal.h>
/* PATH_MAX */
#include <limits.h>
/* str* */
#include <string.h>
/* sockets */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include "cinit.h"
/***********************************************************************
* create a socket, when we recieved a signal
*/
int main(int argc, char **argv)
{
struct sockaddr_un addr;
struct pollfd plist;
char *initdir;
list = NULL; /* list of services is empty currently */
initdir = CINIT_INIT; /* default init dir */
cpid = getpid();
if(cpid != 1) {
usage(MSG_USAGE,MSG_NOT_ONE);
}
set_signals(ACT_SERV); /* set signal handlers */
/* read args, profile support */
while(argc > 1) {
if( !strncmp(PROFILE, argv[argc-1], strlen(PROFILE)) ) {
initdir = (char *) malloc(
strlen(CINIT_DIR) +
strlen(&argv[argc-1][strlen(PROFILE)]) + 2
);
if(initdir == NULL) {
panic();
}
strcpy(initdir,CINIT_DIR);
strcat(initdir,SLASH);
strcat(initdir,&argv[argc-1][strlen(PROFILE)]);
break;
}
argc--;
}
/* tell the world we are there FIXME: do we really need three calls? */
mini_printf(MSG_CINIT,1); mini_printf(initdir,1); mini_printf("\n",1);
if( chdir(CINIT_INIT) == -1) {
perror(MSG_CHDIR);
panic();
}
/******************** TMPDIR **********************/
if( mount(C_TMPMOUNT,CINIT_TMNT,C_TMPFS,0,NULL) == -1 ) {
perror(MSG_ERR_MOUNT);
panic();
}
/******************** begin socket **********************/
sock = socket(AF_UNIX,SOCK_STREAM,0); /* create socket */
if( sock == -1 ) {
perror(MSG_SOCKET);
panic();
}
memset(&addr, 0, sizeof(addr) ); /* clear addr */
strcpy(addr.sun_path, CINIT_SOCK);
addr.sun_family = AF_UNIX;
if(bind(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1) {
perror(MSG_BIND);
panic();
}
/* start listening */
if(listen(sock,SOCK_QUEUE) == -1) {
perror(MSG_LISTEN);
panic();
}
/* start init or profile */
run_init_svc(initdir);
/* free, if we malloc()ed before */
if(initdir != CINIT_INIT) {
free(initdir);
}
/* our life is polling a socket */
plist.fd = sock;
plist.events = POLLIN | POLLPRI;
while(1) {
if(poll(&plist, 1, -1) != -1) {
if( (plist.revents & POLLIN) == POLLIN ||
(plist.revents & POLLPRI) == POLLPRI) {
sigio(sock);
}
}
}
}

View file

@ -0,0 +1,141 @@
/*
* cinit
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* handle client requests
*/
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <signal.h>
#include "cinit.h"
/***********************************************************************
* sigio: client handling
*/
/* we are called, if one or _more_ connections are waiting */
void sigio(int socket)
{
int tmp, nsock;
char buf[PATH_MAX+1], status;
struct listitem *list_tmp;
pid_t pid;
while ( (nsock = accept(socket,(struct sockaddr *) NULL,
(socklen_t *) NULL)) != -1) {
if( read(nsock,&buf[0],1) == -1) {
perror(MSG_ERR_READ);
close(nsock);
continue;
}
switch(buf[0]) {
/********************** START SERVICE *******************/
case CMD_START_SVC:
tmp = do_svc_name(nsock,buf,ACT_SERV);
if(!tmp) break;
buf[tmp] = 0;
list_tmp = list_search(buf);
if(list_tmp != NULL) { /* service already exists, return status */
status = list_tmp->status;
do_result(nsock,&status);
break;
}
tmp = list_insert(buf,ST_TMP); /* add service */
if(!tmp) { /* failed */
LOG(MSG_ERR_ADD_SVC);
status = ST_FAIL;
} else {
status = RT_TMPNOW;
}
do_result(nsock,&status);
break;
/********************** STOP (RESPAWNING) *******************/
case CMD_STOP_SVC:
tmp = do_svc_name(nsock,buf,ACT_SERV);
if(!tmp) break;
buf[tmp] = 0;
list_tmp = list_search(buf);
/* FIXME:
- handle off
- handle switching off once services
- perhaps remove old cinit code, which has respawing childs
*/
if(list_tmp != NULL) { /* service exists */
if(list_tmp->status == ST_RESPAWN) {
/* kill cinit watcher, which kills the real process */
kill(list_tmp->pid,SIGTERM);
/* wait for watcher to terminate */
waitpid(list_tmp->pid,&tmp,0);
}
status = ST_OFF;
if(!list_modify(buf,status,list_tmp->pid)) {
status = ST_FAIL;
} else { /* return status */
status = list_tmp->status;
}
} else { /* no service there */
status = RT_NOTEXIST;
}
do_result(nsock,&status);
break;
/********************** CHANGE SERVICE STATUS *******************/
case CMD_CHG_STATUS:
tmp = do_change_status(buf,&status,&pid,nsock,ACT_SERV);
if(!tmp) break;
buf[tmp] = 0; /* terminate buf */
if(!list_modify(buf,status,pid)) {
SERVICE_LOG(buf,MSG_ERR_MODIFY);
status = 0;
}
do_result(nsock,&status);
break;
/********************** SPECIAL ACTIONS *******************/
case CMD_REBOOT:
sig_reboot(SIGHUP);
break;
case CMD_POWEROFF:
sig_reboot(SIGTERM);
break;
case CMD_HALT:
sig_reboot(SIGUSR1);
break;
case CMD_RESCUE:
sig_reboot(SIGUSR2);
break;
case CMD_UPDATE:
sig_reboot(SIGCONT);
break;
default:
LOG(MSG_CMD_UNKNOWN);
break;
}
close(nsock);
}
/* hier kommt man haeufiger herein, interrupted system call */
if( errno != EAGAIN && errno != EINTR) { /* report, but don't panic */
perror(MSG_ERR_ACCEPT);
}
}

View file

@ -0,0 +1,38 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run_svc
* part of cinit
*/
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h> /* memset, strcpy */
#include "cinit.h"
/* open socket connection to cinit-serv and close original socket */
int connect_sock(int socke)
{
int nsock;
struct sockaddr_un addr;
close(socke);
nsock = socket(PF_UNIX,SOCK_STREAM,0);
if( nsock == -1 ) {
perror(MSG_SOCKET);
return -1;
}
socke = sizeof(addr);
memset(&addr,0,socke);
strcpy(addr.sun_path, CINIT_SOCK);
addr.sun_family = AF_UNIX;
if(connect(nsock,(struct sockaddr *)&addr,socke) == -1) {
return -1;
}
return nsock;
}

View file

@ -0,0 +1,22 @@
Build a small library that can be used by different applications, that provides:
Constants / Macros:
for cinit_halt:
CINIT_HALT
CINIT_REBOOT
CINIT_POWEROFF
for cinit_svc_start/stop:
CINIT_SVC_NORMAL
CINIT_SVC_NEEDS
CINIT_SVC_ONLY
CINIT_SVC_WANTS
Functions:
void cinit_halt(int how);
int cinit_svc_start(char *svc, int how);
int cinit_svc_stop(char *svc, int how);
int cinit_svc_stop(char *svc, int how);
This lib must then include:
- choosen ipc functions

View file

@ -0,0 +1,30 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Retrieves status of a service
*/
#include <string.h> /* str* */
#include <stdint.h> /* integers */
#include "cinit.h" /* header for clients */
/* returns either the status (>0)
* or -1 on memory error
*/
int32_t cinit_get_svc_status(char *name)
{
struct cinit_question qsn;
struct cinit_answer asr;
qsn.cmd = CINIT_MSG_GET_STATUS;
strcpy((qsn.data), name);
qsn.options = 0;
if(!cinit_send_to(&qsn, &asr)) return -1;
return asr.ret;
}

View file

@ -0,0 +1,33 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Retrieves version of cinit
*/
#include <stdlib.h> /* malloc */
#include <string.h> /* str*, memset */
#include <stdio.h> /* NULL */
#include "cinit.h" /* header for clients */
int cinit_get_version(char *buf)
{
struct cinit_question ask;
struct cinit_answer asr;
memset(&ask, '\0', sizeof(ask));
memset(&asr, '\0', sizeof(asr));
ask.cmd = CINIT_MSG_GET_VERSION;
if(!cinit_send_to(&ask, &asr)) return 0;
if(asr.ret != CINIT_MSG_OK) return 0;
/* buf is always big enough to save the version string */
strcpy(buf, asr.data);
return 1;
}

View file

@ -0,0 +1,24 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* cinit_halt(): call for library
*/
#include "" /* include global header */
int cinit_halt(int how)
{
switch(how) {
case 'p': /* power off */
break;
default:
break;
}
}
return 1;
}

View file

@ -0,0 +1,21 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* sends data from the client to cinit
*/
#include "ipc.h" /* IPC */
#include "cinit.h" /* struct cinit_message */
int cinit_send_to(struct cinit_question *data, struct cinit_answer *res)
{
if(!cinit_ipc_logon()) return 0;
if(!cinit_ipc_csend(data)) return 0;
if(!cinit_ipc_cread(res)) return 0;
if(!cinit_ipc_logoff()) return 0;
return 1;
}

View file

@ -0,0 +1,33 @@
/***********************************************************************
*
* 2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* Retrieves status of a service
*/
#include <string.h> /* str* */
#include "cinit.h" /* header for clients */
/* returns either the status (>0)
* or -1 on memory error
*/
pid_t cinit_svc_get_pid(char *name)
{
struct cinit_question qsn;
struct cinit_answer asr;
qsn.cmd = CINIT_MSG_GET_PID;
strcpy((qsn.data), name);
qsn.options = 0;
if(!cinit_send_to(&qsn, &asr)) return -1;
if(asr.ret == CINIT_MSG_OK) {
return asr.options;
} else {
return (pid_t) 0;
}
}

View file

@ -0,0 +1,54 @@
core/build_argv.o
core/cinit.o
core/panic.o
core/set_signals.o
core/do_reboot.o
core/sig_child.o
generic/execute_sth.o
generic/file_exists.o
generic/mini_printf.o
generic/path_absolute.o
generic/path_append.o
generic/print_errno.o
generic/openreadclose.o
generic/strip_final_newline.o
generic/sleep_before_kill.o
generic/execute_and_wait.o
ipc/current/cinit_ipc_init.o
ipc/current/cinit_ipc_listen.o
ipc/current/cinit_ipc_destroy.o
ipc/current/cinit_ipc_logon.o
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o
svc/gen_svc_tree.o
svc/gen_halt_tree.o
svc/list_delete.o
svc/list_insert.o
svc/list_search.o
svc/list_search_pid.o
svc/svc_create.o
svc/check_add_deps.o
svc/dep_entry_add.o
svc/dep_entry_del.o
svc/shutdown_services.o
svc/tree_exec.o
svc/svc_set_status.o
svc/svc_should_respawn.o
svc/svc_needs_status.o
svc/dep_needs_wants_add.o
svc/dep_create.o
svc/svc_success.o
svc/svc_report_status.o
svc/svc_start.o
svc/svc_fail.o
comm/read_command.o
comm/answer_svc_status.o
comm/answer_svc_pid.o
comm/answer_version.o

View file

@ -0,0 +1,11 @@
client/cmd.o
generic/print_errno.o
generic/mini_printf.o
libcinit/cinit_get_svc_status.o
libcinit/cinit_get_version.o
libcinit/cinit_send_to.o
ipc/current/cinit_ipc_logon.o
ipc/current/cinit_ipc_csend.o
ipc/current/cinit_ipc_cread.o
ipc/current/cinit_ipc_logoff.o
libcinit/cinit_svc_get_pid.o

View file

@ -0,0 +1,3 @@
client/halt.kill.o
generic/print_errno.o
generic/mini_printf.o

View file

@ -0,0 +1,3 @@
client/poweroff.kill.o
generic/print_errno.o
generic/mini_printf.o

View file

@ -0,0 +1,3 @@
client/reboot.kill.o
generic/print_errno.o
generic/mini_printf.o

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* halt the system
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_halt(void)
{
reboot(RB_HALT);
}

View file

@ -0,0 +1,3 @@
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* poweroff
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_poweroff(void)
{
reboot(RB_POWEROFF);
}

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* reboot the system
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_reboot(void)
{
reboot(RB_AUTOBOOT);
}

View file

@ -0,0 +1,16 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* How to halt the system
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_halt(void)
{
reboot(RB_HALT_SYSTEM);
}

View file

@ -0,0 +1,3 @@
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* poweroff the system
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_poweroff(void)
{
reboot(RB_POWER_OFF);
}

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* reboot the system
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_reboot(void)
{
reboot(RB_AUTOBOOT);
}

View file

@ -0,0 +1,19 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* poweroff
*
*/
#define _NETBSD_SOURCE 1
#include <unistd.h> /* reboot */
#include <sys/reboot.h> /* reboot */
#include <stdio.h> /* NULL */
void cinit_halt(void)
{
reboot(RB_HALT,NULL);
}

View file

@ -0,0 +1,3 @@
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o

View file

@ -0,0 +1,19 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* poweroff
*
*/
#define _NETBSD_SOURCE 1
#include <unistd.h> /* reboot */
#include <sys/reboot.h> /* reboot */
#include <stdio.h> /* NULL */
void cinit_poweroff(void)
{
reboot(RB_HALT|RB_POWERDOWN,NULL);
}

View file

@ -0,0 +1,19 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* poweroff
*
*/
#define _NETBSD_SOURCE 1
#include <unistd.h> /* reboot */
#include <sys/reboot.h> /* reboot */
#include <stdio.h> /* NULL */
void cinit_reboot(void)
{
reboot(RB_AUTOBOOT,NULL);
}

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* halt the system
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_halt(void)
{
reboot(RB_HALT);
}

View file

@ -0,0 +1,3 @@
os/current/halt.o
os/current/poweroff.o
os/current/reboot.o

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* poweroff
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_poweroff(void)
{
reboot(RB_HALT | RB_POWERDOWN);
}

View file

@ -0,0 +1,17 @@
/***********************************************************************
*
* 2005-2007 Nico Schottelius (nico-cinit at schottelius.org)
*
* part of cLinux/cinit
*
* reboot the system
*
*/
#include <unistd.h>
#include <sys/reboot.h>
void cinit_reboot(void)
{
reboot(RB_AUTOBOOT);
}

Some files were not shown because too many files have changed in this diff Show more