关于MINI SHELL ~ 先谢过
学校要我们做一个MINI SHELL的程序~ 我对C 一窍不通~ 所以在网上找了个程序` 不知道对不对~ 我们老师是法国人, 所以下面会有 法语的解释,大侠们可以略过。 能帮我解释下MINI SHELL 的用处和检查下这个程序吗?
感激不敬 我的 QQ 号 51622131 或跟帖 谢谢 了 ~
由于是新号 可能不能给太多分~ 但我一定记住的账号 日后再报
MINI SHELL
*/
/* en-tetes standard */
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h> /* pour avoir wait & co. */
#include <ctype.h> /* pour avoir isspace & co. */
#include <string.h>
#include <errno.h> /* pour avoir errno */
#include <signal.h>
#include <fcntl.h>
char ligne[4096]; /* contient la ligne d'entree */
/* pointeurs sur les mots de ligne (voir decoupe) */
#define MAXELEMS 32
char* elems[MAXELEMS];
void affiche_invite()
{
printf("> ");
fflush(stdout);
}
void lit_ligne()
{
/* fgets peut etre interrompu par le signal SIGCHLD => on boucle */
while (1) {
if (fgets(ligne,sizeof(ligne)-1,stdin)) break; /* lecture OK */
if (feof(stdin)) {
/* vrai fin */
printf("\n");
exit(0);
}
}
}
/* decoupe ligne en mots
fait pointer chaque elems[i] sur un mot different
elems se termine par NULL
*/
void decoupe()
{
char* debut = ligne;
int i;
for (i=0; i <MAXELEMS-1; i++) {
/* saute les espaces */
while (*debut && isspace(*debut)) debut++;
/* fin de ligne ? */
if (!*debut) break;
/* on se souvient du debut de ce mot */
elems[i] = debut;
/* cherche la fin du mot */
while (*debut && !isspace(*debut)) debut++; /* saute le mot */
/* termine le mot par un \0 et passe au suivant */
if (*debut) { *debut = 0; debut++; }
}
elems[i] = NULL;
}
/* XXX
front_pid = pid du processus au premier plan
permet a sigchld de notifier a execute que la commande au premier
plan vient de se terminer
la variable etant partagee entre le programme principal (lance_commande) et
un handler de signal asynchrone (sigchld), elle dont etre marquee volatile
*/
volatile int front_pid = -1;
void sigchld(int signal)
{
/* un signal peut correspondre a plusieurs fils finis, donc on boucle */
while (1) {
int status;
pid_t pid = waitpid(-1,&status,WNOHANG);
if (pid <0) {
if (errno==EINTR) continue; /* interrompu => on recommence */
if (errno==ECHILD) break; /* plus de fils termine=> on quitte */
printf("erreur de wait (%s)\n",strerror(errno));
break;
}
if (pid==0) break; /* plus de fils termine=> on quitte */
/* XXX signale a execute que front_pid s'est termine*/
if (pid==front_pid) front_pid = -1;
if (WIFEXITED(status))
printf("terminaison normale, pid=%i, status %i\n",pid,WEXITSTATUS(status));
if (WIFSIGNALED(status))
printf("terminaison par signal %i, pid=%i\n",WTERMSIG(status),pid);
}
}
void execute()
{
sigset_t sigset;
pid_t pid;
int en_fond;
char* buffer = (char*)calloc(1024, sizeof(char));
/* XXX detection du & */
if (strchr(ligne,'&')) {
*strchr(ligne,'&') = 0;
en_fond = 1;
}
else {
/* bloque SIGCHLD jusqu'à ce que le pare ait place le pid du
fils dans front_pid
sinon on risque de manquer la notification de fin du fils
(race condition)
*/
sigemptyset(&sigset);
sigaddset(&sigset,SIGCHLD);
sigprocmask(SIG_BLOCK,&sigset,NULL);
en_fond = 0;
}
decoupe();
if (!elems[0]) return; /* ligne vide */
pid = fork();
if (pid < 0) {
printf("fork a achoue(%s)\n",strerror(errno));
return;
}
if (pid==0) {
/* fils */
if (en_fond) {
/* XXX redirection de l'entree standard sur /dev/null */
int devnull = open("/dev/null",O_RDONLY);
if (devnull != -1) {
close(0);
dup2(devnull,0);
}
}
else {
/* XXX reactivation de SIGINT & debloque SIGCLHD */
struct sigaction sig;
sig.sa_flags = 0;
sig.sa_handler = SIG_DFL;
sigemptyset(&sig.sa_mask);
sigaction(SIGINT,&sig,NULL);
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
}
if (strcmp(elems[0],"cd") == 0) {
// change directory
int count_arg=0;
while(elems[count_arg]!=NULL){count_arg++;}
printf("nb : %d\n",count_arg);
if ((count_arg) == 2) {
if (chdir(strcat ( strcat (getcwd(buffer, 1024),"/"), strcat (elems[1],"/") )) != 0) {
printf("Error: Invalid directory. %s\n",getcwd(buffer, 1024));
}
} else {
printf("Error: Invalid use of cd command.\n");
}
}
else{
execvp(elems[0], /* programme a executer */
elems /* argv du programme a executer */
);
printf("impossible d'executer \"%s\" (%s)\n",elems[0],strerror(errno));
exit(1);
}
}
else {
if (!en_fond) {
/* XXX attent la fin du processus au premier plan */
printf("pid %i\n",pid);
front_pid = pid;
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
/* attente bloquante jusqu'à ce que sigchld signale que front_pid
s'est termine*/
while (front_pid!=-1) pause();
}
}
}
int main()
{
struct sigaction sig;
sig.sa_flags = 0;
sig.sa_handler = sigchld;
sigemptyset(&sig.sa_mask);
sigaction(SIGCHLD,&sig,NULL);
sig.sa_handler = SIG_IGN;
sigaction(SIGINT, &sig, NULL);
while (1) {
affiche_invite();
lit_ligne();
execute();
}
return 0;
}