您的位置:首页 > 运维架构 > Shell

OS之子进程简单模拟shell解释环境(再次)

2016-01-12 17:22 453 查看
(1)当输入一条指令后,将指令拆分成独立的符号;

(2)如果指令的最后一个符号是’&’,则(4)子进程执行指令的时候,父进程将不会wait()子进程执行完毕,继续接收下一条指令进行解释;

(3)History指令由主程序使用循环队列进行维护,最多只记录10条历史指令;'!!'执行最近执行过的指令,'! + 数字'执行对应的历史指令;

(4)如果是非history指令,fork()一个子进程,调用execvp()进行解释执行;

一、主程序

/*
** FILE: osh.c
** NOTE: 2016-01-11 created by Jack Liu
** DESC:
*/
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"history.h"

#define MAX_HISTORY 10

/* how many stokens */
int stoken_cmd_num( char *cpCmd );
/* split the command into stokens */
char **stoken_cmd( char *cpCmd, int *iTokenNum );
/* remember the command */
int do_history( char *cpCmd, PHISTORY_LIST pHistory );
/* when children terminate, recycle it */
void child_fun( int sig );

int
main( void )
{
char caCmd[ MAX_CMD ];
char **cppCmdStokens;
pid_t pid;
int  iTokenNum;
int  iConcurrent;
struct sigaction newSigAct, oldSigAct;
HISTORY_LIST history;

newSigAct.sa_handler = child_fun;
if( sigaction( SIGCHLD, &newSigAct, &oldSigAct ) < 0 )
{
perror( "sigaction" );
return -1;
}

if( history_init( &history, MAX_HISTORY ) < 0 )
{
fprintf( stderr, "fail to init history list\n" );
return -1;
}

while( 1 )
{
int i = 0;
iConcurrent = 0;
printf( "osh>" );

/*
** get the input command
*/
if( fgets( caCmd, MAX_CMD, stdin ) == NULL )
{   /* the user want to exit, ctrl + D */
putchar( '\n' );
break;
}
if( caCmd[ strlen( caCmd ) - 1 ] == '\n' )
caCmd[ strlen( caCmd ) - 1 ] = '\0';

if( caCmd[ 0 ] == '\0' )  /* just input enter, ignore it */
continue;

/*
** record the command
*/
if( do_history( caCmd, &history ) < 0 )
continue;

/*
** split the command
*/
if( strcmp( caCmd, "exit" ) == 0 )
{   /* the user want to exit, input exit */
break;
}

cppCmdStokens = stoken_cmd( caCmd, &iTokenNum );
if( cppCmdStokens == NULL )
{
fprintf( stderr, "couldn't recognize: %s\n", caCmd );
continue;
}

/*
** fork a child to exec the command
** or
** print the history commands
*/
if( cppCmdStokens[ iTokenNum - 2 ][ strlen( cppCmdStokens[ iTokenNum - 2 ] ) - 1 ] == '&' )
{
iConcurrent = 1;    /* concurrent the command */
/*
** clear the '&' character
*/
cppCmdStokens[ iTokenNum - 2 ][ strlen( cppCmdStokens[ iTokenNum - 2 ] ) - 1 ] = '\0';
if( cppCmdStokens[ iTokenNum - 2 ][ 0 ] == '\0' )
{   /* '&' occupy a stoken, clear the stoken */
free( cppCmdStokens[ iTokenNum - 2 ] );
cppCmdStokens[ iTokenNum - 2 ] = NULL;
}
}

if( strcmp( cppCmdStokens[ 0 ], "history" ) == 0 )
{
history_print( &history );
}
else
{
if( ( pid = fork() ) < 0 )
{
fprintf( stderr, "fail to exec: %s\n", caCmd );
continue;
}
else if( pid == 0 )
{   /* child */
execvp( cppCmdStokens[ 0 ], cppCmdStokens );
fprintf( stderr, "fail to exec: %s\n", caCmd );
exit( -1 );
}
}

i = 0;
/*
** clear stokens
*/
while( cppCmdStokens[ i ] )
free( cppCmdStokens[ i++ ] );
free( cppCmdStokens );

if( !iConcurrent ) /* wait the child to exec */
waitpid( pid, NULL, 0 );
}
history_clear( &history );
return 0;
}

int
stoken_cmd_num( char *cpCmd )
{
char caTmpCmd[ MAX_CMD ];
char *cpIndex;
int  iNum = 0;
if( cpCmd == NULL )
{
fprintf( stderr, "Illegal cmd\n" );
return -1;
}
strncpy( caTmpCmd, cpCmd, MAX_CMD );

cpIndex = strtok( caTmpCmd, " " );
while( cpIndex )
{
iNum++;
cpIndex = strtok( NULL, " " );
}

return iNum;
}

char **
stoken_cmd( char *cpCmd, int *iTokenNum )
{
char caTmpCmd[ MAX_CMD ];
char *cpIndex;
char *cpStoken;
char **cppStokens;
int  iNum;
if( cpCmd == NULL )
{
fprintf( stderr, "Illegal command line\n" );
return NULL;
}
strncpy( caTmpCmd, cpCmd, MAX_CMD );
if( ( iNum = stoken_cmd_num( cpCmd ) ) > 0 )
{
/*
** the last element is NULL
*/
*iTokenNum = iNum + 1;
cppStokens = malloc( sizeof( char * ) * ( iNum + 1 ) );
if( cppStokens == NULL )
{
perror( "malloc" );
return NULL;
}
}
else
{
fprintf( stderr, "Illegal command line\n" );
return NULL;
}
memset( cppStokens, 0x00, sizeof( char * ) * ( iNum + 1 ) );

/*
** begin to split
*/
iNum = 0;
cpIndex = strtok( caTmpCmd, " " );
while( cpIndex )
{
if( ( cpStoken = malloc( strlen( cpIndex ) + 1 ) ) == NULL )
{
int i;
for( i = 0; i < iNum; i++ )
free( cppStokens[ i ] );
free( cppStokens );
perror( "malloc" );
return NULL;
}
memset( cpStoken, 0x00, strlen( cpIndex ) + 1 );
strcpy( cpStoken, cpIndex );
cppStokens[ iNum++ ] = cpStoken;
cpIndex = strtok( NULL, " " );
}
cppStokens[ iNum ] = NULL;

return cppStokens;
}

int
do_history( char *cpCmd, PHISTORY_LIST pHistory )
{
PHISTORY_RECORD pRecord;
int iIndex = -1;
char caTmpCmd[ MAX_CMD ] = { 0 };
if( cpCmd[ 0 ] == '!' )
{
memcpy( caTmpCmd, cpCmd + 1, strlen( cpCmd ) ); /* include the NULL-terminated */
if( strcmp( caTmpCmd, "!" ) != 0 )
iIndex = atoi( caTmpCmd );
else
iIndex = 1;

if( iIndex <= 0 || iIndex > pHistory->iLen )
{
fprintf( stderr, "no such history command\n" );
return -1;
}

pRecord = history_index( pHistory, iIndex );
if( pRecord == NULL )
{
fprintf( stderr, "no such history command\n" );
return -1;
}
strcpy( cpCmd, pRecord->cpCmd );
}
else
{   /* record the command */
pRecord = history_get_record( cpCmd );
history_pushback( pHistory, pRecord );
}

return 0;
}

void
child_fun( int sig )
{
waitpid( -1, NULL, WNOHANG );
}


二、history队列维护头文件

/*
** FILE: history.h
** NOTE: 2016-01-11 created by Jack Liu
** DESC: manage the historic commands up to 10
*/
#ifndef COM_JACKLIU_HISTORY_H
#define COM_JACKLIU_HISTORY_H

#define MAX_CMD 512

typedef struct history_record
{
char cpCmd[ MAX_CMD ];
struct history_record *prev;
struct history_record *next;
} HISTORY_RECORD, *PHISTORY_RECORD;

typedef struct history_list
{
PHISTORY_RECORD front;
PHISTORY_RECORD rear;
int iLen;
int iMax;
} HISTORY_LIST, *PHISTORY_LIST;

int history_init( PHISTORY_LIST list, int iMax );
PHISTORY_RECORD history_get_record( char *cpCmd );
int history_pushback( PHISTORY_LIST list, PHISTORY_RECORD record );
PHISTORY_RECORD history_pop( PHISTORY_LIST list );
PHISTORY_RECORD history_front( PHISTORY_LIST list );
PHISTORY_RECORD history_index( PHISTORY_LIST list, int iIndex );
int history_print( PHISTORY_LIST list );
int history_clear( PHISTORY_LIST list );

#endif


三、history队列维护实现

/*
** FILE: history.c
** NOTE: 2016-01-11 created by Jack Liu
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "history.h"

int
history_init( PHISTORY_LIST list, int iMax )
{
if( list == NULL )
{
fprintf( stderr, "history operation: init error, list argument illegal\n" );
return -1;
}
list->front = list->rear = NULL;
list->iLen = 0;
list->iMax = iMax;

return 0;
}

PHISTORY_RECORD
history_get_record( char *cpCmd )
{
PHISTORY_RECORD pRecord;

pRecord = malloc( sizeof( HISTORY_RECORD ) );
if( pRecord == NULL )
{
perror( "malloc" );
return NULL;
}
memset( pRecord, 0x00, sizeof( HISTORY_RECORD ) );

strcpy( pRecord->cpCmd, cpCmd );
return pRecord;
}

int
history_pushback( PHISTORY_LIST list, PHISTORY_RECORD pRecord )
{
if( list == NULL || pRecord == NULL )
{
fprintf( stderr, "illegal operation: list is empty\n" );
return -1;
}

if( list->rear == NULL )
{   /* first record */
list->front = pRecord;
pRecord->prev = pRecord->next = NULL;
}
else
{
list->rear->next = pRecord;
pRecord->prev = list->rear;
pRecord->next = NULL;
}
list->rear = pRecord;
list->iLen++;
if( list->iLen > list->iMax )
{
PHISTORY_RECORD pToFree = list->front;
list->front = list->front->next;
list->front->prev = NULL;
free( pToFree );
list->iLen = list->iMax;
}

return 0;
}

PHISTORY_RECORD
history_pop( PHISTORY_LIST list )
{
PHISTORY_RECORD pRecord;
if( list == NULL )
{
fprintf( stderr, "history operation: list is illegal\n" );
return NULL;
}

if( list->rear == NULL )
return NULL; /* the history list is emtpy */

pRecord = list->rear;
list->rear = list->rear->prev;

if( list->rear == NULL ) /* now list is empty */
list->front = NULL;
else
list->rear->next = NULL;

return pRecord;
}

PHISTORY_RECORD
history_front( PHISTORY_LIST list )
{
PHISTORY_RECORD pRecord;
if( list == NULL )
{
fprintf( stderr, "history operation: list is illegal\n" );
return NULL;
}

if( list->front == NULL )
return NULL;     /* history list is empty */

pRecord = list->front;
list->front = list->front->next;

if( list->front == NULL ) /* now list is empty */
list->rear = NULL;
else
list->front->prev = NULL;

return pRecord;
}

PHISTORY_RECORD
history_index( PHISTORY_LIST list, int iIndex )
{
PHISTORY_RECORD pRecord;
int i;
if( list == NULL )
{
fprintf( stderr, "history operation: list is illegal\n" );
return NULL;
}

if( list->front == NULL )
{
fprintf( stderr, "history operation: list is emtpy\n" );
return NULL;
}

if( iIndex > list->iLen )
{
fprintf( stderr, "no such history command\n" );
return NULL;
}

i = 1;
pRecord = list->rear;
while( ++i <= iIndex )
pRecord = pRecord->prev;

return pRecord;
}

int
history_print( PHISTORY_LIST list )
{
PHISTORY_RECORD pRecord;
int i;
if( list == NULL )
{
fprintf( stderr, "history operation: history list is empty\n" );
return -1;
}

i = list->iLen;
pRecord = list->front;
while( i > 0 )
{
printf( "%02d %s\n", i--, pRecord->cpCmd );
pRecord = pRecord->next;
}

return 0;
}

int
history_clear( PHISTORY_LIST list )
{
if( list != NULL )
{
PHISTORY_RECORD pRecord;
while( ( pRecord = history_front( list ) ) )
free( pRecord );
}

return 0;
}


四、源代码

http://download.csdn.net/detail/qq123386926/9401186
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: