exsh-2.c
by
管理者
—
last modified
2006-07-27 01:48
Click here to get the file
Size
4.4 kB
-
File type
text/x-csrc
File contents
/*
* $Id: exsh-2.c,v 1.30 2006/05/31 10:35:38 yamamoto Exp yamamoto $
*
* (C) Copyright: S.Yamamoto 2006
* This file is a product of the project Exsh.
*/
#include <setjmp.h> /* For setjmp() and longjmp(). */
#include <signal.h> /* For sigaction(). */
#include <stdarg.h> /* For variable argument lists. */
#include <stdio.h>
#include <stdlib.h> /* For EXIT_SUCCESS. */
#include <string.h> /* For strtok(). */
#include <sys/types.h> /* For pid_t. */
#include <sys/wait.h> /* For waitpid(). */
#include <unistd.h> /* For execl() family. */
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
#define MAX_INPUT 81 /* Including a terminator. */
/* Including a command name, 8 arguments and a NULL terminator. */
#define ARG_MAX (1 + 8 +1)
#define JMP_SIGINT 1 /* Return value from longjmp(). */
static int debug_mode = FALSE;
static char input[MAX_INPUT];
static sigjmp_buf jmp;
static void set_signal_handler(void);
static void parse_input(char x[MAX_INPUT], char *a[ARG_MAX]);
static void read_command(char *a[ARG_MAX]);
static void handler_sigint(int x);
static void debug(const char *format, ...);
int main(int argc, char *argv[])
{
int status;
pid_t pid;
/* Initialize. */
if (2 <= argc && !strcmp(argv[1], "-d")) {
debug_mode = TRUE;
}
set_signal_handler();
debug("getpid() %d.\n", getpid());
while (TRUE) {
char *args[ARG_MAX];
int ret_setjmp;
ret_setjmp = sigsetjmp(jmp, 1);
debug("getpid() %d, setjmp(): %d.\n", getpid(), ret_setjmp);
if (ret_setjmp != 0) { /* longjmp() occurred. */
fputs("\n", stderr);
continue;
}
read_command(args);
if (args[0] == NULL) {
continue;
}
if ((pid = fork()) < 0) { /* Error. */
perror(NULL);
} else if (pid == 0) { /* Child. */
int retval;
debug("Child: getpid() %d, fork() %d.\n", getpid(), pid);
retval = execvp(args[0], args);
perror(args[0]);
exit(EXIT_FAILURE);
} else { /* Parent. */
debug("Parent: getpid() %d, fork() %d.\n", getpid(), pid);
waitpid(pid, &status, 0);
}
}
exit (EXIT_SUCCESS);
}
/*
* シグナルハンドラを設定する.
*/
static void set_signal_handler(void)
{
static struct sigaction action;
action.sa_handler = handler_sigint; /* シグナルハンドラ. */
/* ハンドラ内でSIGINTをブロックする. */
sigemptyset(&action.sa_mask); /* マスクのクリア. */
sigaddset(&action.sa_mask, SIGINT);
action.sa_flags = SA_RESTART; /* BSDとの互換性(おまじない). */
sigaction(SIGINT, &action, NULL); /* SIGINTに設定.*/
}
static void read_command(char *a[ARG_MAX])
{
if (isatty(fileno(stdin))) { /* Only in case of terminal. */
fputs("> ", stderr);
}
gets(input);
if (feof(stdin)) {
exit(EXIT_SUCCESS);
}
debug("\"%s\".\n", input);
if (!strcmp(input, "exit")) {
exit (EXIT_SUCCESS);
}
parse_input(input, a);
}
/*
* Return value:
* a[0]: command name.
* a[1] ... a[n]: arguments followed by a NULL terminator.
*
* If input is a empty string, a[0] is NULL.
*/
static void parse_input(char x[MAX_INPUT], char *a[ARG_MAX])
{
int i = 0;
a[i] = strtok(x, " ");
debug("a[%d] \"%s\".\n", i, a[i]);
i++;
while (a[i - 1] != NULL) {
if (ARG_MAX <= i) {
fprintf(stderr, "Too many arguments.\n");
a[0] = NULL;
break;
}
a[i] = strtok(NULL, " ");
debug("a[%d] \"%s\".\n", i, a[i]);
i++;
};
}
/*
* シグナルハンドラ.
*/
static void handler_sigint(int x)
{
debug("Catch signal SIGINT.\n");
siglongjmp(jmp, JMP_SIGINT);
}
static void debug(const char *format, ...)
{
va_list args;
if (!debug_mode) {
return;
}
fflush(stdout);
fflush(stderr);
fputs("Debug: ", stderr);
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fflush(stderr);
}