*** empty log message ***

This commit is contained in:
Jorrit Herder
2005-08-23 11:31:32 +00:00
parent 10e4e98947
commit 7bf400a709
11 changed files with 83 additions and 28 deletions

View File

@@ -1,141 +0,0 @@
/* This file contains procedures to manage the system processes.
*
* The entry points into this file are
* do_start:
* do_stop:
* do_exit: a child of this server exited
*
* Changes:
* Jul 22, 2005: Created (Jorrit N. Herder)
*/
#include "sm.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <minix/dmap.h>
extern int errno;
#define EXEC_FAILED 49 /* arbitrary, recognizable status */
#define MAX_PATH_LEN 256 /* maximum path string length */
#define MAX_ARGS_LEN 4096 /* maximum argument string length */
#define MAX_ARG_COUNT 1 /* parsed arguments count */
PRIVATE char command[MAX_PATH_LEN+1];
PRIVATE char arg_buf[MAX_ARGS_LEN+1];
/*===========================================================================*
* do_start *
*===========================================================================*/
PUBLIC int do_start(message *m_ptr)
{
message m;
int child_proc_nr;
int major_nr;
enum dev_style dev_style;
pid_t child_pid;
char *args[MAX_ARG_COUNT+1];
int s;
/* Obtain command name and parameters. */
if (m_ptr->SRV_PATH_LEN > MAX_PATH_LEN) return(E2BIG);
if (OK != (s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->SRV_PATH_ADDR,
SELF, (vir_bytes) command, m_ptr->SRV_PATH_LEN))) return(s);
command[m_ptr->SRV_PATH_LEN] = '\0';
if (command[0] != '/') return(EINVAL);
args[0] = command;
if (m_ptr->SRV_ARGS_LEN > 0) {
if (m_ptr->SRV_ARGS_LEN > MAX_ARGS_LEN) return(E2BIG);
if (OK != (s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->SRV_ARGS_ADDR,
SELF, (vir_bytes) arg_buf, m_ptr->SRV_ARGS_LEN))) return(s);
arg_buf[m_ptr->SRV_ARGS_LEN] = '\0';
args[1] = &arg_buf[0];
args[2] = NULL;
} else {
args[1] = NULL;
}
/* Now try to execute the new system service. Fork a new process. The child
* process will be inhibited from running by the NO_PRIV flag. Only let the
* child run once its privileges have been set by the parent.
*/
if ((s = _taskcall(PM_PROC_NR, FORK, &m)) < 0) /* use raw interface */
report("SM", "_taskcall to PM failed", s); /* to get both */
child_pid = m.m_type; /* - child's pid */
child_proc_nr = m.PR_PROC_NR; /* - process nr */
/* Now branch for parent and child process, and check for error. */
switch(child_pid) { /* see fork(2) */
case 0: /* child process */
execve(command, args, NULL); /* POSIX exec */
report("SM", "warning, exec() failed", errno); /* shouldn't happen */
exit(EXEC_FAILED); /* terminate child */
break;
case -1: /* fork failed */
report("SM", "warning, fork() failed", errno); /* shouldn't happen */
return(errno);
default: /* parent process */
if ((major_nr = m_ptr->SRV_DEV_MAJOR) > 0) { /* set driver map */
dev_style = STYLE_DEV;
if ((s=mapdriver(child_proc_nr, major_nr, dev_style)) < 0) {
#if VERBOSE
printf("SM: '%s %s', major %d, pid %d, proc_nr %d",
command, arg_buf, major_nr, child_pid, child_proc_nr);
#endif
report("SM", "couldn't map driver", errno);
}
}
if ((s = _taskcall(SYSTEM, SYS_PRIVCTL, &m)) < 0) /* set privileges */
report("SM", "_taskcall to SYSTEM failed", s); /* to let child run */
#if VERBOSE
printf("SM: started '%s %s', major %d, pid %d, proc_nr %d",
command, arg_buf, major_nr, child_pid, child_proc_nr);
#endif
/* update tables */
}
return(OK);
}
/*===========================================================================*
* do_stop *
*===========================================================================*/
PUBLIC int do_stop(message *m_ptr)
{
return(ENOSYS);
}
/*===========================================================================*
* do_exit *
*===========================================================================*/
PUBLIC int do_exit(message *m_ptr)
{
pid_t exit_pid;
int exit_status;
#if VERBOSE
printf("SM: got SIGCHLD signal, doing wait to get exited child.\n");
#endif
/* See which child exited and what the exit status is. This is done in a
* loop because multiple childs may have exited, all reported by one
* SIGCHLD signal. The WNOHANG options is used to prevent blocking if,
* somehow, no exited child can be found.
*/
while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) {
#if VERBOSE
printf("SM: pid %d,", exit_pid);
if (WIFSIGNALED(exit_status)) {
printf("killed, signal number %d\n", WTERMSIG(exit_status));
} else if (WIFEXITED(exit_status)) {
printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
}
#endif
}
return(OK);
}

View File

@@ -1,10 +0,0 @@
/* Function prototypes. */
/* sm.c */
_PROTOTYPE( void main, (void));
/* manager.c */
_PROTOTYPE( int do_exit, (message *m));
_PROTOTYPE( int do_start, (message *m));
_PROTOTYPE( int do_stop, (message *m));

View File

@@ -1,179 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <minix/config.h>
#include <minix/com.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/ipc.h>
#include <minix/syslib.h>
#include <sys/types.h>
#include <sys/stat.h>
/* This array defines all known requests. */
PRIVATE char *known_requests[] = {
"up",
"down",
"catch for illegal requests"
};
#define ILLEGAL_REQUEST sizeof(known_requests)/sizeof(char *)
/* Global error number set for failed system calls. */
#define OK 0
extern int errno;
/* Define names for arguments provided to this utility. The first few
* arguments are required and have a known index. Thereafter, some optional
* argument pairs like "-args arglist" follow.
*/
#define ARG_NAME 0 /* own application name */
#define ARG_REQUEST 1 /* request to perform */
#define ARG_PATH 2 /* binary of system service */
#define MIN_ARG_COUNT 3 /* minimum number of arguments */
#define ARG_ARGS "-args" /* list of arguments to be passed */
#define ARG_DEV "-dev" /* major device number for drivers */
#define ARG_PRIV "-priv" /* required privileges */
/* The function parse_arguments() verifies and parses the command line
* parameters passed to this utility. Request parameters that are needed
* are stored globally in the following variables:
*/
PRIVATE int req_type;
PRIVATE char *req_path;
PRIVATE char *req_args;
PRIVATE int req_major;
PRIVATE char *req_priv;
/* An error occurred. Report the problem, print the usage, and exit.
*/
PRIVATE void print_usage(char *app_name, char *problem)
{
printf("Warning, %s\n", problem);
printf("Usage:\n");
printf(" %s <request> <binary> [%s <args>] [%s <special>]\n",
app_name, ARG_ARGS, ARG_DEV);
printf("\n");
}
/* An unexpected, unrecoverable error occurred. Report and exit.
*/
PRIVATE void panic(char *app_name, char *mess, int num)
{
printf("Panic in %s: %s", app_name, mess);
if (num != NO_NUM) printf(": %d", num);
printf("\n");
exit(EGENERIC);
}
/* Parse and verify correctness of arguments. Report problem and exit if an
* error is found. Store needed parameters in global variables.
*/
PRIVATE int parse_arguments(int argc, char **argv)
{
struct stat stat_buf;
int i;
/* Verify argument count. */
if (! argc >= MIN_ARG_COUNT) {
print_usage(argv[ARG_NAME], "wrong number of arguments");
exit(EINVAL);
}
/* Verify request type. */
for (req_type=0; req_type< ILLEGAL_REQUEST; req_type++) {
if (strcmp(known_requests[req_type],argv[ARG_REQUEST])==0) break;
}
if (req_type == ILLEGAL_REQUEST) {
print_usage(argv[ARG_NAME], "illegal request type");
exit(ENOSYS);
}
/* Verify the name of the binary of the system service. */
req_path = argv[ARG_PATH];
if (req_path[0] != '/') {
print_usage(argv[ARG_NAME], "binary should be absolute path");
exit(EINVAL);
}
if (stat(req_path, &stat_buf) == -1) {
print_usage(argv[ARG_NAME], "couldn't get status of binary");
exit(errno);
}
if (! (stat_buf.st_mode & S_IFREG)) {
print_usage(argv[ARG_NAME], "binary is not a regular file");
exit(EINVAL);
}
/* Check optional arguments that come in pairs like "-args arglist". */
for (i=MIN_ARG_COUNT; i<argc; i=i+2) {
if (! (i+1 < argc)) {
print_usage(argv[ARG_NAME], "optional argument not complete");
exit(EINVAL);
}
if (strcmp(argv[i], ARG_ARGS)==0) {
req_args = argv[i+1];
}
else if (strcmp(argv[i], ARG_DEV)==0) {
if (stat(argv[i+1], &stat_buf) == -1) {
print_usage(argv[ARG_NAME], "couldn't get status of device node");
exit(errno);
}
if ( ! (stat_buf.st_mode & (S_IFBLK | S_IFCHR))) {
print_usage(argv[ARG_NAME], "special file is not a device node");
exit(EINVAL);
}
req_major = (stat_buf.st_rdev >> MAJOR) & BYTE;
}
else if (strcmp(argv[i], ARG_ARGS)==0) {
req_priv = argv[i+1];
}
else {
print_usage(argv[ARG_NAME], "unknown optional argument given");
exit(EINVAL);
}
}
/* Return the request number if no error were found. */
return(i);
}
/* Main program.
*/
PUBLIC int main(int argc, char **argv)
{
message m;
int result;
int s;
/* Verify and parse the command line arguments. All arguments are checked
* here. If an error occurs, the problem is reported and exit(2) is called.
* all needed parameters to perform the request are extracted and stored
* global variables.
*/
parse_arguments(argc, argv);
/* Arguments seem fine. Try to perform the request. Only valid requests
* should end up here. The default is used for not yet supported requests.
*/
switch(req_type+SRV_RQ_BASE) {
case SRV_UP:
m.SRV_PATH_ADDR = req_path;
m.SRV_PATH_LEN = strlen(req_path);
m.SRV_ARGS_ADDR = req_args;
m.SRV_ARGS_LEN = strlen(req_args);
m.SRV_DEV_MAJOR = req_major;
if (OK != (s=_taskcall(SM_PROC_NR, SRV_UP, &m)))
panic(argv[ARG_NAME], "sendrec to manager server failed", s);
result = m.m_type;
break;
case SRV_DOWN:
case SRV_STATUS:
default:
print_usage(argv[ARG_NAME], "request is not yet supported");
result = EGENERIC;
}
return(result);
}

View File

@@ -1,130 +0,0 @@
/* System Process Manager.
*
* Created:
* Jul 22, 2005 by Jorrit N. Herder
*/
#include "sm.h"
/* Set debugging level to 0, 1, or 2 to see no, some, all debug output. */
#define DEBUG_LEVEL 1
#define DPRINTF if (DEBUG_LEVEL > 0) printf
/* Allocate space for the global variables. */
message m_in; /* the input message itself */
message m_out; /* the output message used for reply */
int who; /* caller's proc number */
int callnr; /* system call number */
/* Declare some local functions. */
FORWARD _PROTOTYPE(void init_server, (void) );
FORWARD _PROTOTYPE(void get_work, (void) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
/*===========================================================================*
* main *
*===========================================================================*/
PUBLIC void main(void)
{
/* This is the main routine of this service. The main loop consists of
* three major activities: getting new work, processing the work, and
* sending the reply. The loop never terminates, unless a panic occurs.
*/
int result;
sigset_t sigset;
/* Initialize the server, then go to work. */
init_server();
/* Main loop - get work and do it, forever. */
while (TRUE) {
/* Wait for incoming message, sets 'callnr' and 'who'. */
get_work();
switch (callnr) {
case SYS_SIG:
/* Signals are passed by means of a notification message from SYSTEM.
* Extract the map of pending signals from the notification argument.
*/
sigset = (sigset_t) m_in.NOTIFY_ARG;
if (sigismember(&sigset, SIGCHLD)) {
/* A child of this server exited. Take action. */
do_exit(&m_in);
}
if (sigismember(&sigset, SIGUSR1)) {
do_start(&m_in);
}
if (sigismember(&sigset, SIGTERM)) {
/* Nothing to do on shutdown. */
}
if (sigismember(&sigset, SIGKSTOP)) {
/* Nothing to do on shutdown. */
}
continue;
case SRV_UP:
result = do_start(&m_in);
break;
case SRV_DOWN:
result = do_stop(&m_in);
break;
default:
printf("Warning, SM got unexpected request %d from %d\n",
m_in.m_type, m_in.m_source);
result = EINVAL;
}
/* Finally send reply message, unless disabled. */
if (result != EDONTREPLY) {
reply(who, result);
}
}
}
/*===========================================================================*
* init_server *
*===========================================================================*/
PRIVATE void init_server(void)
{
/* Initialize the information service. */
int i, s;
struct sigaction sa;
/* Install signal handlers. Ask PM to transform signal into message. */
sa.sa_handler = SIG_MESS;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGCHLD, &sa, NULL)<0) panic("SM","sigaction failed", errno);
if (sigaction(SIGTERM, &sa, NULL)<0) panic("SM","sigaction failed", errno);
if (sigaction(SIGABRT, &sa, NULL)<0) panic("SM","sigaction failed", errno);
if (sigaction(SIGHUP, &sa, NULL)<0) panic("SM","sigaction failed", errno);
}
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE void get_work()
{
int status = 0;
status = receive(ANY, &m_in); /* this blocks until message arrives */
if (OK != status)
panic("SM","failed to receive message!", status);
who = m_in.m_source; /* message arrived! set sender */
callnr = m_in.m_type; /* set function call number */
}
/*===========================================================================*
* reply *
*===========================================================================*/
PRIVATE void reply(who, result)
int who; /* destination */
int result; /* report result to replyee */
{
int send_status;
m_out.m_type = result; /* build reply message */
send_status = send(who, &m_out); /* send the message */
if (OK != send_status)
panic("SM", "unable to send reply!", send_status);
}

View File

@@ -1,35 +0,0 @@
/* Header file for the system service manager server.
*
* Created:
* Jul 22, 2005 by Jorrit N. Herder
*/
#define _SYSTEM 1 /* get OK and negative error codes */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define VERBOSE 0 /* display diagnostics */
#include <ansi.h>
#include <sys/types.h>
#include <limits.h>
#include <errno.h>
#include <signal.h>
#include <minix/callnr.h>
#include <minix/config.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/keymap.h>
#include <minix/bitmap.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include "proto.h"