Unix环境高级编程实验总结

       前两周把apue这门课的实验给做完了,base代码是从网上找到的,看着里面有一堆的父子线程的调用就头大,按照实验要求没做的那么复杂,关键是没花时间去做这方面的实验,把进程相关的代码都删掉了,只是添加了一些基本的的类shell命令的函数,又写了一个简单的Makefile,由于最开始的想法是先都添加在一个.c文件中将功能全部都实现,再把函数按照功能一个一个拆分成不同的.c文件,但是往里添加的时候没有标记相关变量和宏是属于哪个头文件,功能都实现之后发现要把相关函数以及他们的头文件拆分出来太浪费时间,真是教训!最后一周做实验,没有那么多的时间,所以为了用Makefile这个装逼lity一点的编译方式而不是gcc这种lame的方式,只好把main.c文件单独拆出,剩下的所有功能得的函数都放在一个.c文件中,勉强做了个Makefile,实在拙劣,有机会再重新弄吧!

一.实验要求:

1.实验目的

理解shell程序的功能。

学会shell的使用。

构造一个简单的shell。

2.实验内容

基本任务:用 C/C++编写一个简单的 Shell 程序,实现以下基本的命令。

1)  浏览目录和文件的各种属性 ls, ls –l

2)  回显 echo

3)  显示文件内容 cat, more ...

4)  创建目录 mkdir

5)  删除目录 rmdir

6)  删除文件 rm

7)  改变目录 cd

8)  改变文件和目录的权限 chmod

9)  显示当前目录 pwd

10)  文字统计wc

11)  查看时间命令 date, time

12)  退出命令exit

13)  发送信号命令kill

14)  查看在线用户who

15)  查看命令历史记录history

16)  执行用户的程序

17)  help 功能

选做任务:

提供友好的人机界面; 提供帮助功能;

写一个 makefile 来管理

3. 要求

  1. 独立完成实验内容。
  2. 良好的编程风格。
  3. 注意事项。
  4. 禁止使用 system/exec 等函数直接调用系统 shell 提供的内在命令。 对于执行指定的程序,使用 fork 函数生成一个新进程执行。
  5. 必须有 exit 命令:用来退出 shell
  6. 必须有 help 命令:列出 shell 所拥有的所有命令。
  7. 实验提交。

二.功能介绍:

1.基本功能:

该程序具有基本的shell命令功能,具体如下:1)  浏览目录和文件的各种属性 ls, ls –l;2)  回显 echo;3)  显示文件内容 cat, more ...;4)  创建目录 mkdir;5)  删除目录 rmdir;6)  删除文件 rm;7)  改变目录 cd;8)  改变文件和目录的权限 chmod;9)  显示当前目录 pwd;10)  文字统计wc;11)  查看时间命令 date, time;12)  退出命令exit;13)  发送信号命令kill;14)  查看在线用户who;15)  查看命令历史记录history;16)  help 功能

2.扩展功能:1)  查看进程信息ps;2)  清屏clr;3)  查看环境变量environ

三.使用方法:

1)在shell窗口中进入程序所在文件夹

2)输入make指令,编译完会生成imitateShell可执行文件

3)./imitateShell,执行该文件,进入仿shell程序,即可执行所有的基本仿shell指令功能。

四.编译方法:

由makefile统一对.c文件和.h文件进行编译,makefile内容如下:

imitateSh:imitateShellMultiFounc.c

gcc main.c imitateShellMultiFounc.c -o imitateShell

clean:

rm -fr *.o *.pre ./lib/*.pre $(PROGS)

五.软件设计文档:

1.软件构成:

该程序是由2个.c文件和3个自定义.h构成,.c文件分别是mian.c和imitateShellMultiFounc.c ,imitateShellMultiFounc.c 文件包含所有仿shell指令函数的定义,main.c调用imitateShellMultiFounc.c 中的函数来完成指令的运行。

2.程序简易流程图:

 

 

六.用户操作手册:

1.进入WQshell程序

 

2. ls

 

3.ll

4.echo

5.catmore:按回车多显示下面一行,按空格+回车显示多行

6. mkdir

 

7.rmdir

 

8.rm

 

9.cdpwd

 

10.wc

 

11.chmod

 

12.date

13.time

 

14.kill

15.who


16.help


17.exit

       至于代码真的是没什么好解释的,代码部分是原base里的,部分是我在网上找到类似的添加进去的,对了history这个功能我在网上没找到,自己写了一个,就简单说一下吧,这个功能就是查看输入的历史指令,跟原shell命令不一样的是,它只记录了命令,没有记录命令后的其他参数,若要记录完整的指令也是很好添加的,因为每次输入的指令都会被cmd_array[]数组保存,cmd_array[0]存的是具体指令,如:ls,kill,wc,echo......,而cmd_array[1] 存放的是指令后所带的第一个参数,cmd_array[2]存放的是指令后所带的第二个参数,比如kill -9 2345 ,cmd_array[0]存的是"kill",cmd_array[1]存的是"-9",cmd_array[2]存的是"2345",注意向kill()函数里传参数时要将其转换为数字。接着说history功能,就是将每次输入的指令以追加的方式"at+"保存到一个txt文件中,执行history指令时再将指令从txt文件按行读出,这样就和原shell的histiry指令类似了。

/********************将指令写入历史文件*****************************/
int CommWriteHisFile(char *comm) //将command指令存入history文件
{
	FILE *fp = NULL;
	if((fp=fopen("history.txt","at+"))==NULL)
	{
		printf("cannot open file\n");
		return 0;
	}
	fputs(comm,fp);
	fputs("\n",fp);
	fclose(fp);
	fp = NULL;
	return 0;
}
/*****************************************************************/


/********************从历史文件中读出指令*****************************/
void FileReadComm() //读取文件中的指令
{
	FILE *stream; 
	char line[10]; 
	if( (stream = fopen( "history.txt", "r" )) != NULL ) 
	{ 
		while(fgets(line,10,stream)!=NULL) 
		{ 
			printf( "%s", line); 
		} 
		printf("\n"); 
		fclose( stream ); 
	} 
}
/*****************************************************************/

下面是Makefike的内容(很简单,省得敲gcc了):

imitateSh:imitateShellMultiFounc.c
	gcc main.c imitateShellMultiFounc.c -o imitateShell

clean:
	rm -fr *.o *.pre ./lib/*.pre $(PROGS)

下面把源码粘贴:

main.c

/***************************************************************************
*Project Name: main.c
*Auther:Frankwang
*Student ID:1120171293
*Last Modified: 2018.4.21
***************************************************************************/
/*自定义*/
#include<stdio.h>
#include<stdlib.h>
#define MAX_LINE 80//最大命令长度
int main(){
	int should_run=1;//标记什么时候退出大循环
	int cmd_len=0;//记录命令长度
	fopen("history.txt","w+");//清空history指令
	welcome();//欢迎信息
	while(should_run){
		printprompt();//打印命令提示符
		readcommand();//读取命令,同时也取得了cmd_cnt的值
		cmd_len=getcommandlen();
		if(cmd_len>MAX_LINE){//如果用户输入长度超过规定的长度
			printf("the length of your input is too long to be read in\n");
			exit(1);
		}
		if(is_internal_cmd()){//处理内部命令
			continue;
		}
	}
	return 0;
}

imitateShellMultiFounc.c

/***************************************************************************
*Project Name: WQshell
*Auther:Frankwang
*Student ID:1120171293
*Last Modified: 2018.4.21
***************************************************************************/ 
/*自定义*/
#include"command_comm.h"
#include"err_msg.h"
#include"file_isexist.h"
/*系统*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<memory.h>
#include<math.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<sys/param.h>
#include<sys/times.h>  
#include<sys/time.h>  
#include<pwd.h>
#include<errno.h>
#include<time.h>
#include<fcntl.h>
#include<dirent.h>
#include<signal.h>
#include<grp.h>
#include<getopt.h>
#include<utmp.h>
/*和长度有关的宏定义*/
#define MAX_LINE 80//最大命令长度
#define MAX_NAME_LEN 100//最大用户名长度
#define MAX_PATH_LEN 1000//最大路径长度

/*more*/
#define PAGELEN 24
#define LINELEN 514

/*time*/
#define err_exit(m) {perror(m); exit(1);}  

/*全局变量申明*/
extern char **environ;//必须用extern申明,否则会报错
char *cmd_array[MAX_LINE/2+1];//保存命令输入,就是原框架的char* args[]
int cmd_cnt;//命令中字符串的个数

void readcommand();//读取用户输入
int is_internal_cmd();//处理内部命令

/*自己定义的函数*/
void welcome();//打印欢迎信息,带有颜色
void printprompt();//打印提示符,必须包含当前路径名
int getcommandlen();//计算命令长度
void myquit();//quit,退出myshell
void myexit();//exit,直接退出
void myclr();//clr,和BatchShell下的clear一样
void mypwd();//pwd,打印当前工作目录
void myecho();//echo,必须支持重定向
void myecho_redirect();//带重定向的echo
void mytime();//time,和"date"类似
void myenviron();//environ,和env一样,必须支持重定向
void myenviron_redirect();//带重定向的environ
void mycd();//cd,切换到某个目录
void myhelp();//help,必须支持重定向
void myhelp_redirect();//带有重定向的help
void print_manual();//打印用户手册,是myhelp()的子函数 
void print_cmdinfo(char* cmdname);//打印每个命令的帮助信息,是myhelp()的子函数
void mytest();//test,检查文件类型,支持-l,-b,-c,-d四个选项
void myumask();//umask,查看默认的umask值或者重置umask
void myjobs();//jobs,查看正在运行的进程

/***************************功能:wc ********************************/
struct wc_option
{
    unsigned char           c;      /*  显示字节数  */
    unsigned char           l;      /*  显示行数    */
    unsigned char           w;      /*  显示单词数  */
};

struct wc_count
{
    unsigned int            c;
    unsigned int            l;
    unsigned int            w;
};

struct wc_option            g_option;
struct wc_count             g_count;

static int
char_is_in(char c, const char *str, size_t len)
{
    size_t                  i;

    for(i = 0; i < len; ++i)
        if(str[i] == c)
            return 1;

    return 0;
}

static unsigned int
getwordcount(char *buf)
{
    const char              *word_sep = " \r\f\t\v\n";
    unsigned int            word_count = 0;
    char                    *token;
    size_t                  total_size = strlen(buf);

    if(buf == NULL || buf[0] == 0)
        return 0;
    /*  去前面的无关字符    */
    {
        while(total_size > 0 && char_is_in(buf[0], word_sep, strlen(word_sep)))
        {
            --total_size;
            buf++;
        }

    }

    /*  去掉后面的无关字符  */
    {
        while(total_size > 0 && char_is_in(buf[total_size], word_sep, strlen(word_sep)))
        {
            buf[total_size] = 0;
            --total_size;
        }
    }

    token = strtok(buf, word_sep);
    while(token)
    {
        ++word_count;
        token = strtok(NULL, word_sep);
    }

    return word_count;
}

static void
pr_wc(const char *file)
{
    if(g_option.c == 0 && g_option.l == 0 && g_option.w == 0)
    {
        printf("%u\t%u\t%u\t%s\n", g_count.l, g_count.w, g_count.c, file);
        return;
    }

    if(g_option.l != 0)
        printf("%u\t", g_count.l);
    if(g_option.w != 0)
        printf("%u\t", g_count.w);
    if(g_option.c != 0)
        printf("%u\t", g_count.c);

    printf("%s\n", file);
}

static int
wc(const char *file)
{
    FILE            *fp;
    char            buf[MAX_LINE_BUF_SIZE];

    if(!file_isreg(file))
    {
        pr_msg("file [%s] is not access or is not a simple file\n", file);
        return 1;
    }

    if((fp = fopen(file, "r")) == NULL)
    {
        pr_msg("open file [%s] error [%s]\n", file, strerror(errno));
        return 1;
    }

    memset(&g_count, 0, sizeof(g_count));
    while(fgets(buf, MAX_LINE_BUF_SIZE, fp) != NULL)
    {
        ++g_count.l;
        g_count.c += strlen(buf);
        g_count.w += getwordcount(buf);
    }


    pr_wc(file);
    return 0;
}

/******************************************************************/



/*******************功能:ls -l *************************************/
void show_file_info(char* filename, struct stat* info_p)
{
    char* uid_to_name(), *ctime(), *gid_to_name(), *filemode();
    void mode_to_letters();
    char modestr[11];

    mode_to_letters(info_p->st_mode, modestr);

    printf("%s", modestr);
    printf(" %4d", (int) info_p->st_nlink);
    printf(" %-8s", uid_to_name(info_p->st_uid));
    printf(" %-8s", gid_to_name(info_p->st_gid));
    printf(" %8ld", (long) info_p->st_size);
    printf(" %.12s", 4 + ctime(&info_p->st_mtime));
    printf(" %s\n", filename);
}

void mode_to_letters(int mode, char str[])
{
    strcpy(str, "----------");

    if (S_ISDIR(mode))
    {
        str[0] = 'd';
    }

    if (S_ISCHR(mode))
    {
        str[0] = 'c';
    }

    if (S_ISBLK(mode))
    {
        str[0] = 'b';
    }

    if ((mode & S_IRUSR))
    {
        str[1] = 'r';
    }

    if ((mode & S_IWUSR))
    {
        str[2] = 'w';
    }

    if ((mode & S_IXUSR))
    {
        str[3] = 'x';
    }

    if ((mode & S_IRGRP))
    {
        str[4] = 'r';
    }

    if ((mode & S_IWGRP))
    {
        str[5] = 'w';
    }

    if ((mode & S_IXGRP))
    {
        str[6] = 'x';
    }

    if ((mode & S_IROTH))
    {
        str[7] = 'r';
    }

    if ((mode & S_IWOTH))
    {
        str[8] = 'w';
    }

    if ((mode & S_IXOTH))
    {
        str[9] = 'x';
    }
}

char* uid_to_name(uid_t uid)
{
    struct passwd* getpwuid(),* pw_ptr;
    static char numstr[10];

    if((pw_ptr = getpwuid(uid)) == NULL)
    {
        sprintf(numstr,"%d",uid);

        return numstr;
    }
    else
    {
        return pw_ptr->pw_name;
    }
}

char* gid_to_name(gid_t gid)
{
    struct group* getgrgid(),* grp_ptr;
    static char numstr[10];

    if(( grp_ptr = getgrgid(gid)) == NULL)
    {
        sprintf(numstr,"%d",gid);
        return numstr;
    }
    else
    {
        return grp_ptr->gr_name;
    }
}

void dostat(char* filename)
{
    struct stat info;
    
    if (stat(filename, &info) == -1)
    {
        perror(filename);
    }
    else
    {
        show_file_info(filename, &info);
    }
}

void do_ls(char dirname[])
{
    DIR* dir_ptr;
    struct dirent* direntp;

    if ((dir_ptr = opendir(dirname)) == NULL)
    {
        fprintf(stderr, "ls2: cannot open %s \n", dirname);
    }
    else
    {
        while ((direntp = readdir(dir_ptr)) != NULL)
        {
            dostat(direntp->d_name);
        }

        close(dir_ptr);
    }
}

/*****************************************************************/


/*************************cat,more*******************************/
void do_more(FILE *fp)
{
    char line[LINELEN];
    //int see_more();
    int reply;
    int number_line = 0;
    while(fgets(line, LINELEN, fp) != NULL)
    {
        if(number_line == PAGELEN)
        {
            reply = see_more();
            if(reply == 0) 
              break;
            number_line -= reply;
        }
        if( fputs(line, stdout) == EOF)
          exit(1);
        number_line ++;
    }
}

int see_more()
{
    int c;
    printf("\033[7m more? \033[m");
    while( (c = getchar()) != EOF )
    {
        if(c == 'q')
          return 0;
        if(c == ' ')
          return PAGELEN;
        if(c == '\n')
          return 1;
    }
    return 0;
}

/*****************************************************************/


/**********************who instruction*****************************/
int pr_who()
{
    struct utmp         *u;
    char                timebuf[128];

	// getutent()用来从utmp 文件(/var/run/utmp)中读取一项登录数据, 该数据以utmp 结构返回。
	// 第一次调用时会取得第一位用户数据, 之后每调用一次就会返回下一项数据, 直到已无任何数据时返回NULL。
    while((u = getutent()))
    {
        /*  去除一些不需要显示的项  */
        if(u->ut_type != USER_PROCESS)
            continue;
        ctime_r(&(u->ut_tv.tv_sec), timebuf);
        if(timebuf[0] != 0)
            timebuf[strlen(timebuf)-1] = 0; /*去掉'\n'*/
        printf("%-12s%-12s%-20.20s  (%s)\n",
               u->ut_user,
               u->ut_line,
               timebuf,
               u->ut_host);
    }

    endutent();
    return 1;
}
/*****************************************************************/


/********************将指令写入历史文件*****************************/
int CommWriteHisFile(char *comm)	//将command指令存入history文件
{
	FILE *fp = NULL;
	if((fp=fopen("history.txt","at+"))==NULL)
	{
		printf("cannot open file\n");
		return 0;
	}
	fputs(comm,fp);
	fputs("\n",fp);
	//putchar(str);
	fclose(fp);
	fp = NULL;
	return 0;
}
/*****************************************************************/


/********************从历史文件中读出指令*****************************/
void FileReadComm()	//读取文件中的指令
{
FILE *stream;  
   char line[10];  
  
   if( (stream = fopen( "history.txt", "r" )) != NULL )  
   {  
       while(fgets(line,10,stream)!=NULL)  
       {  
         printf( "%s", line);  
       }  
       printf("\n");  
      fclose( stream );  
   }  
}
/*****************************************************************/



/**********************time***************************************/
//#define BUF_SIZE    512  
//#define FILE_NAME   "demo.txt"  
int caltime(){  
	int clocks_per_sec;    		//每秒时钟数  
	struct  tms st_tms;             //times函数的机构  
	clock_t start = clock();        //记录起始时间, 
	 
	if(strcmp(cmd_array[1],"ls")==0){
		do_ls(".");
	}
	else if(strcmp(cmd_array[1],"echo")==0){
		myecho();
	}
	else if(strcmp(cmd_array[1],"cat")==0){
		FILE *fp;
		if( (fp = fopen(cmd_array[2], "r")) != NULL) // 打开文件 
		{
			printf("%s\n", cmd_array[2]);
			do_more(fp);
			fclose(fp);
		}
	}
	else if(strcmp(cmd_array[1],"mkdir")==0){
		mkdir(cmd_array[2], 0744);//8进制:文件所有者具有读、写、执行权限 /用户组具可读取权限  /其他用户具可读取权限
	}
	else if(strcmp(cmd_array[1],"rmdir")==0){
		rmdir(cmd_array[2]);
	}
	else if(strcmp(cmd_array[1],"rm")==0){
		unlink(cmd_array[2]);
	}
	else if(strcmp(cmd_array[1],"cd")==0){
		mycd();
	}
	else if(strcmp(cmd_array[1],"chmod")==0){
		chmod(cmd_array[3],strtol( cmd_array[2], NULL, 8 ));//strtol最后一个参数设置为8会将字符串转换成对应8进制数
	}
	else if(strcmp(cmd_array[1],"pwd")==0){
		mypwd();
	}
	else if(strcmp(cmd_array[1],"wc")==0){
		wc(cmd_array[2]);
	}
	else if(strcmp(cmd_array[1],"date")==0){
		mytime();
	}
	//else if(strcmp(*arr1,"time")==0){
	//	caltime(cmd_array[1],cmd_array[2],cmd_array[3]);
	//}
	else if(strcmp(cmd_array[1],"kill")==0){
		kill(atoi(cmd_array[2]),cmd_array[3]);//进程号/具体的信号 kill(pid,SIGCONT);
	}
	else if(strcmp(cmd_array[1],"history")==0){
		FileReadComm();
	}
	else if(strcmp(cmd_array[1],"help")==0){
		myhelp();
	}

	if (times(&st_tms) == -1) err_exit("times error");  
	clock_t end = clock();  
	printf("%d\n",start);
	printf("%d\n",end);
	clocks_per_sec = sysconf(_SC_CLK_TCK);  //用于获得times函数的单位时钟数  
	printf("real  times: %7dus\n", (end-start)*1000);  
	printf("user  times: %7dus\n", st_tms.tms_utime*1000000/(clocks_per_sec));  
	printf("syst  times: %7dus\n", st_tms.tms_stime*1000000/(clocks_per_sec));  
	return 1;  
}  
/*****************************************************************/



/*实现顺序和定义顺序相同*/
void readcommand(){
	//这个函数用来读取用户输入
	int exit_status = 0;
	int cnt=0;//记录cmd_array[]中字符串的个数
	char str[MAX_LINE];
	char* helper;
	memset(cmd_array,0,MAX_LINE/2+1);//每次必须清空!
	fgets(str,MAX_LINE,stdin);//用fgets代替gets,因为gets不检查溢出,比较危险
	if(str[strlen(str)-1]=='\n'){
		str[strlen(str)-1]='\0';//fgets会补'\n',这里必须把'\n'替换成'\0'
	}
	helper=strtok(str," ");//用空格分割这个命令
	while(helper!=NULL){//将分割后得到的结果写进cmd_array
			cmd_array[cnt]=(char*)malloc(sizeof(*helper));
			strcpy(cmd_array[cnt++],helper);//注意:即便直接回车cmd_cnt也是1
			helper=strtok(NULL," ");
	}
	cmd_cnt=cnt;//cmd_cnt的值就是cnt的值
}

int is_internal_cmd(){
	//这个函数用来解析内部命令
	//根据不同的结果来调用不同函数来达到目的
	if(cmd_array[0]==NULL){//如果没有命令(只是回车)
		return 0;//返回0使得主函数的continue不执行

	}

	else if(strcmp(cmd_array[0],"ls")==0){
		CommWriteHisFile("ls");
		printf("重写的ls -l\n");
		do_ls(".");
		return 1;

	}

	else if(strcmp(cmd_array[0],"echo")==0){//echo
		int i;
		CommWriteHisFile("echo");
		for(i=1;i<cmd_cnt;i++){//从第二个字符串开始分析
			if(strcmp(cmd_array[i],">")==0||strcmp(cmd_array[i],">>")==0){//如果有重定向符号
				//myecho_redirect();//调用带有重定向的echo
				return 1;
			}
		}
		myecho();//如果没有重定向,直接echo
		return 1;

	}

	else if(strcmp(cmd_array[0],"cat")==0){//cat和more功能
		CommWriteHisFile("cat");
		printf("重写的cat/more\n");
		FILE *fp;
		if( (fp = fopen(cmd_array[1], "r")) != NULL) // 打开文件 
		{
			printf("%s\n", cmd_array[1]);
			do_more(fp);
			fclose(fp);
		}
		return 1;

	}

	else if(strcmp(cmd_array[0],"mkdir")==0){
		CommWriteHisFile("mkdir");
		printf("重写的mkdir\n");
		mkdir(cmd_array[1], 0744);//8进制:文件所有者具有读、写、执行权限 /用户组具可读取权限  /其他用户具可读取权限
		return 1;

	}

	else if(strcmp(cmd_array[0],"rmdir")==0){
		CommWriteHisFile("rmdir");
		printf("重写的rmdir\n");
		rmdir(cmd_array[1]);
		return 1;

	}

	else if(strcmp(cmd_array[0],"rm")==0){
		CommWriteHisFile("rm");
		printf("重写的rm\n");
		unlink(cmd_array[1]);
		return 1;

	}

	else if(strcmp(cmd_array[0],"cd")==0){//cd,切换目录
		CommWriteHisFile("cd");
		mycd();
		return 1;

	}

	else if(strcmp(cmd_array[0],"chmod")==0){
		CommWriteHisFile("chmod");
		printf("重写的chmod\n");
		//cmd_array[1] = strcat(&a,cmd_array[1]);
		printf("cat :cmd_array[1]=%s\n",cmd_array[1]);
		chmod(cmd_array[2],strtol( cmd_array[1], NULL, 8 ));//strtol最后一个参数设置为8会将字符串转换成对应8进制数
		return 1;

	}

	else if(strcmp(cmd_array[0],"pwd")==0){//pwd,打印当前工作目录
		CommWriteHisFile("pwd");
		mypwd();
		return 1;
	}

	else if(strcmp(cmd_array[0],"wc")==0){
		CommWriteHisFile("wc");
		printf("重写的wc\n");
	    	wc(cmd_array[1]);
		return 1;

	}

	else if(strcmp(cmd_array[0],"date")==0){//date,显示当前时间,和date命令相似
		printf("重写的date\n");
		CommWriteHisFile("date");
		mytime();
		return 1;
	}

	else if(strcmp(cmd_array[0],"time")==0){//time,统计某个命令的运行时间
		printf("重写的time\n");
		caltime();
		return 1;

	}

	else if(strcmp(cmd_array[0],"exit")==0){//exit,直接退出
		CommWriteHisFile("exit");
		myexit();

	}

	else if(strcmp(cmd_array[0],"kill")==0){//???????????有bug
		CommWriteHisFile("kill");
		printf("重写的kill\n");
		kill(atoi(cmd_array[2]),atoi(cmd_array[1]));//进程号/具体的信号 kill(pid,SIGCONT);
		return 1;

	}

	else if(strcmp(cmd_array[0],"who")==0){
		CommWriteHisFile("who");
		printf("重写的who\n");
		exit_status = pr_who();
		return exit_status;

	}

	else if(strcmp(cmd_array[0],"history")==0){
		CommWriteHisFile("history");
		printf("重写的history\n");
		//kill(atoi(cmd_array[1]),cmd_array[2]);//进程号/具体的信号 kill(pid,SIGCONT);
		FileReadComm();
		return 1;

	}

	else if(strcmp(cmd_array[0],"help")==0){//help
		//myhelp();//没有重定向
		if(cmd_array[1]!=NULL&&(strcmp(cmd_array[1],">")==0||strcmp(cmd_array[1],">>")==0)){//带有重定向
			myhelp_redirect();//注意:格式是 "help > filename"或者"help >>filename"
			return 1;
		}
		else{
			myhelp();//没有重定向
			return 1;
		}
		
	}
	
	
	
	
	else if(strcmp(cmd_array[0],"quit")==0){//quit,退出之前有“Thank you...”提示信息
		CommWriteHisFile("quit");
		myquit();

	}

	else if(strcmp(cmd_array[0],"clr")==0){//clr,清屏
		CommWriteHisFile("clr");
		myclr();
		return 1;

	}

	else if(strcmp(cmd_array[0],"ps")==0){//ps,查看运行的进程
		myjobs();
		return 1;

	}

	else if(strcmp(cmd_array[0],"environ")==0){//environ
		CommWriteHisFile("environ");
		if(cmd_array[1]!=NULL&&(strcmp(cmd_array[1],">")==0||strcmp(cmd_array[1],">>")==0)){//带有重定向
			myenviron_redirect();//调用带有重定向的environ
			return 1;
		}
		else{
			myenviron();//没有重定向
			return 1;
		}
	}
	
	else if(strcmp(cmd_array[0],"test")==0){//test,用来查看文件属性,支持[-l],[-d],[-c],[-b]四个选项
		mytest();
		return 1;

	}

	else if(strcmp(cmd_array[0],"umask")==0){//umask,查看或者设置umask值
		myumask();
		return 1;

	}


	else{
		return 0;//返回0使得主函数的continue不执行

	}
}


/*自己定的函数的实现*/
/*实现顺序和定义顺序相同*/
void welcome(){
	//如下是欢迎信息
	//为了是程序更友好,加入了颜色
	//颜色是紫色,背景色与shell相同
	printf("\e[35mmwelcome to WQshell! :-)\e[0m\n");
}

void printprompt(){
	//这个函数用来打印命令提示符
	//为了使程序更友好,加入了颜色
	//颜色是蓝色
	char hostname[MAX_NAME_LEN];
	char pathname[MAX_PATH_LEN];
	struct passwd *pwd;
	pwd=getpwuid(getuid());//通过pid获取用户信息
	gethostname(hostname,MAX_NAME_LEN);//取得hostname
	getcwd(pathname,MAX_PATH_LEN);//获取绝度路径把它储存到第一个参数pathname[]
	printf("\e[34mWQshell>%s@%s:\e[0m",pwd->pw_name,hostname);//打印提示符,颜色是蓝色
	if (strncmp(pathname,pwd->pw_dir,strlen(pwd->pw_dir))==0){//比较两条路径
		printf("~%s",pathname+strlen(pwd->pw_dir));//打印路径
	}
	else {
		printf("%s",pathname);//打印当前工作路径
	}
	if (geteuid()==0) {//函数返回有效用户的id
		printf("#");//如果是root用户,打印#提示符
	}
	else {
		printf("$");//普通用户打印$提示符
	}
}

int getcommandlen(){
	int tot_len=0;
	int i;
	for(i=0;i<cmd_cnt;i++){
		tot_len+=strlen(cmd_array[i]);//注意:空格没有算进去
	}
	return tot_len+cmd_cnt-1;//因此这里要把空格的长度加进去,直接回车返回-1
}

void myquit(){
	printf("Thanks for your using,bye-bye!\n");
	sleep(1);//暂停1s,看上去视觉效果好一些
	exit(0);
}

void myexit(){
	exit(0);//直接退出
}

void myclr(){
	printf("\033[2J");//清屏
	printf("\033[H");//把光标移动到合适的位置
}

void mypwd(){
	char pathname[MAX_PATH_LEN];
	if(getcwd(pathname,MAX_PATH_LEN)){//获取路径名
		printf("%s\n",pathname);
	}
	else{//如果出错
		perror("myshell: getcwd");//报错
		exit(1);
	}
}

void myecho(){
	int i;
	for(i=1;i<cmd_cnt;i++){
		printf("%s",*(cmd_array+i));
		if(i==cmd_cnt-1){//打印最后的字符时不要空格,直接break
			break;
		}
		printf(" ");
	}
	printf("\n");//然后换行
}

void mytime(){
	int weekday;
	int month;
	time_t tvar;
	struct tm *tp;
	time(&tvar);
	tp=localtime(&tvar);//获取本地时间
	weekday=tp->tm_wday;
	switch(weekday){//根据不同的值打印不同的星期
	case 1:
		printf("Mon ");
		break;
	case 2:
		printf("Tues ");
		break;
	case 3:
		printf("Wed ");
		break;
	case 4:
		printf("Thur ");
		break;
	case 5:
		printf("Fri ");
		break;
	case 6:
		printf("Sat ");
		break;
	case 7:
		printf("Sun ");
		break;
	default:
		break;
	}
	month=1+tp->tm_mon;//必须要加1,经过查阅资料:tm_mon比实际的值少了1
	switch(month){//根据不同的值打印月份名
	case 1:
		printf("Jan ");
		break;
	case 2:
		printf("Feb ");
		break;
	case 3:
		printf("Mar ");
		break;
	case 4:
		printf("Apr ");
		break;
	case 5:
		printf("May ");
		break;
	case 6:
		printf("Jun ");
		break;
	case 7:
		printf("Jul ");
		break;
	case 8:
		printf("Aug ");
		break;
	case 9:
		printf("Sep ");
		break;
	case 10:
		printf("Oct ");
		break;
	case 11:
		printf("Nov ");
		break;
	case 12:
		printf("Dec ");
		break;
	default:
		break;
	}
	printf("%d ",tp->tm_mday);//日期
	printf("%d:",tp->tm_hour);//小时
	printf("%d:",tp->tm_min);//分钟
	printf("%d ",tp->tm_sec);//秒
	printf("CST ");//CST,意思是China Standard Time
	printf("%d\n",1900+tp->tm_year);//必须加上1900,返回的值并不是完整的年份,比真实值少了1900
}

void myenviron(){
	//用environ[]来实现全局变量的打印
	//"environ" 必须实现被申明:exetern char** environ
	int i;
	for(i=0;environ[i]!=NULL;i++){
		printf("%s\n",environ[i]);
	}
}

void myenviron_redirect(){
	//把环境变量重定向到文件
	//思路是用dup2()
	//这和上面的重定向相似,但是一些关键的代码是不一样的
	int fd;//文件描述符
	pid_t pid;
	char filename[MAX_NAME_LEN];
	if(cmd_array[2]==NULL){//如果出现错误
		printf("error occurs when redirecting\n");
		exit(1);
	}
	else{
		strcpy(filename,cmd_array[2]);//获取文件名
	}
	if(strcmp(cmd_array[1],">")==0){//>:重写文件内容
		fd=open(filename,O_CREAT|O_TRUNC|O_WRONLY,0600);//必须用O_TRUNC
		if(fd<0){
			perror("myshell: open");
			exit(1);
		}
		if((pid=fork())==0){//子进程
			int i;
			dup2(fd,1);//把stdout重定向到fd
			for(i=0;environ[i]!=NULL;i++){//向文件写内容
				printf("%s\n",environ[i]);
			}			
			exit(0);
		}
		else if(pid>0){//父进程
			waitpid(pid,NULL,0);//等待子进程
		}
		else{
			perror("myshell: fork");
			exit(1);
		}
		close(fd);
	}
	else{//如果是>>
		fd=open(filename,O_CREAT|O_APPEND|O_WRONLY,0600);//必须用O_APPEND
		if(fd<0){
			perror("myshell: open");
			exit(1);
		}
		if((pid=fork())==0){//子进程
			int i;
			dup2(fd,1);//把stdout重定向到fd
			for(i=0;environ[i]!=NULL;i++){
				printf("%s\n",environ[i]);
			}
			exit(0);
		}
		else if(pid>0){//父进程
			waitpid(pid,NULL,0);//等待子进程
		}
		else{
			perror("myshell: fork");
			exit(1);
		}
		close(fd);	
	}
}

void mycd(){
	struct passwd *pwd;//用来获取参数pw_dir
	char pathname[MAX_PATH_LEN];//储存路径名
	pwd=getpwuid(getuid());
	if(cmd_cnt==1){//如果只有一个cd
		strcpy(pathname,pwd->pw_dir);//获取pathname
		if(chdir(pathname)==-1){//如果有错
			perror("myshell: chdir");//报错
			exit(1);
		}
	}
	else{//如果有路径
		if(chdir(cmd_array[1])==-1){//如果chdir执行失败
			printf("myshell: cd: %s :No such file or directory\n",cmd_array[1]);//打印提示信息		
		}	
	}
}

void myhelp(){
	if(cmd_cnt==1){//如果是不带参数的help
		print_manual();//调用子函数print_manual打印用户帮助手册
	}
	else if(cmd_cnt==2){//如果格式是"help [command]"
		print_cmdinfo(cmd_array[1]);//打印单个命令的帮助信息
	}
	else{//如果有错
		printf("myshell: help: Invalid use of help command\n");//打印提示信息
	}
}

void myhelp_redirect(){
	//重定向帮助信息到文件
	//这个函数并不支持"help [command] > filename"这样的格式
	//因为其实和help直接重定向比起来是大同小异
	int fd;//文件描述符
	pid_t pid;
	char filename[MAX_NAME_LEN];
	if(cmd_array[2]==NULL){
		printf("error occurs when redirecting\n");
		exit(1);
	}
	else{
		strcpy(filename,cmd_array[2]);//获取文件名
	}
	if(strcmp(cmd_array[1],">")==0){//>:重写文件内容
		fd=open(filename,O_CREAT|O_TRUNC|O_WRONLY,0600);//必须用O_TRUNC
		if(fd<0){
			perror("myshell: open");
			exit(1);
		}
		if((pid=fork())==0){//子进程
			dup2(fd,1);//把stdout重定向到fd
			print_manual();//打印内容重定向到了文件
			exit(0);
		}
		else if(pid>0){//父进程
			waitpid(pid,NULL,0);//阻塞父进程,等待子进程
		}
		else{
			perror("myshell: fork");
			exit(1);
		}
		close(fd);
	}
	else{//如果是>>重定向
		fd=open(filename,O_CREAT|O_APPEND|O_WRONLY,0600);//必须用O_APPEND
		if(fd<0){
			perror("myshell: open");
			exit(1);
		}
		if((pid=fork())==0){//子进程
			dup2(fd,1);//重定向stdout到fd
			print_manual();//调用print_manual,信息打印到文件
			exit(0);
		}
		else if(pid>0){//父进程
			waitpid(pid,NULL,0);//等待子进程
		}
		else{
			perror("myshell: fork");
			exit(1);
		}
		close(fd);//不要忘记关闭文件
	}
}

void print_manual(){
	//基本任务
	printf("welcome to the manual of myshell, hope it's useful for you\n");
	printf("the following are the BUILT-IN commands supported by myshell\n");
	printf("\n");
	printf("NAMES      FORMATS                         DESCRIPTIONS\n");
	printf("ls:        ls [-l]                  	   list directory contents,[-l]:list directory contents\n");
	printf("echo:      echo [arg ...]                  print strings after echo,redirection is supported\n");
	printf("cat:	   cat [OPTION]... FILE...         concatenate files and print on the standard output\n");
	printf("more:	   more [-dlfpcsu] [-num]          file perusal filter for crt viewing\n");
	printf("mkdir:     mkdir [OPTION]... DIRECTORY...  make directories\n");
	printf("rmdir:     rmdir [OPTION]... DIRECTORY...  remove empty directories\n");
	printf("rm:        rm [OPTION]... FILE...   	   remove files or directories\n");
	printf("chmod:     chmod MODE... FILE...	   change file mode bits\n");
	printf("cd:        cd [dir]			   go to a specified directory\n");
	printf("pwd:       pwd                             print the current working directory\n");
	printf("wc:        wc [FILE]...                    print newline, word, and byte counts for each file\n");
	printf("date:      date                            print or set the system date and time\n");
	printf("exit:      exit                            quit the shell directly\n");
	printf("kill:      kill [options] <pid> [...]      send a signal to a process\n");
	printf("who:       who			           show who is logged on\n");
	printf("history:   history			   GNU History Library\n");
	printf("help:      help			   	   show the manual of help/get help info of a sepcified command\n");
	//选做任务
	printf("ps:        ps                 		   report a snapshot of the current processes\n");
	printf("test:      test [arg ...]                  check file attributes, 4 options are supported so far\n");
	printf("umask:     umask [-p] [-S] [mode]          change the value of umask\n");
	printf("clr:       clr                             clear the screen\n");
	printf("environ:   environ                         list all the environment variables\n");
	printf("quit:      quit                            quit the shell with thank-you information\n");
	printf("for more information, use help [command] to see diffirent options of each command\n");
	fflush(stdout);
}

void print_cmdinfo(char* cmdname){
	//这个函数显示myshell命令的option 
	//需要说明的是[command] --help这样的格式是无效的
	//因为这会带来分析命令是不必要的麻烦
	//正确的格式是help [command]
	if(strcmp(cmdname,"cd")==0){
		printf("usage:go to a specified directory\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

	else if(strcmp(cmdname,"echo")==0){
		printf("usage:print strings after echo,redirection is supported\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}
	else if(strcmp(cmdname,"exec")==0){
		printf("usage:execute a command and replace the current process\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}
	else if(strcmp(cmdname,"exit")==0){
		printf("usage:quit the shell directly\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

	else if(strcmp(cmdname,"ps")==0){
		printf("usage:check the processes running in the system\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

	else if(strcmp(cmdname,"pwd")==0){
		printf("usage:print the current working directory\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

	else if(strcmp(cmdname,"test")==0){
		printf("usage:check file attributes, 4 options are supported so far\n");
		printf("options            descriptions\n");
		printf("[-l]               test if the file is a symbolic link\n");
		printf("[-b]               test if the file is a block device\n");
		printf("[-c]               test if the file is a character device\n");
		printf("[-d]               test if the file is a directory\n");
	}

	else if(strcmp(cmdname,"date")==0){
		printf("usage:show the current time in an elegant format\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

	else if(strcmp(cmdname,"umask")==0){
		printf("usage:change the value of umask\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

	else if(strcmp(cmdname,"clr")==0){
		printf("usage:clear screen\n");
		printf("options            descriptions\n");
		printf("none               see the manual,pls\n");
	}

	else if(strcmp(cmdname,"environ")==0){
		printf("usage:list all the environment variables\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}
	else if(strcmp(cmdname,"help")==0){
		printf("usage:show the manual of help/get help info of a sepcified command\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}
	else if(strcmp(cmdname,"quit")==0){
		printf("usage:quit the shell with thank-you information\n");
		printf("options            descriptions\n");
		printf("none               see the manual,plz\n");
	}

}

void mytest(){
	if(cmd_cnt!=3){//命令中的字符串格式只有3个
		printf("myshell: test: incorrect number of arguments\n");
		printf("the format is 'test [op] [filename]'\n");
		printf("for more information: use 'help test'\n");
	}
	else{
		FILE* fp;
		struct stat buf;
		char filename[MAX_NAME_LEN];
		int mode;//用来保存调用stat()以后的返回结果
		strcpy(filename,cmd_array[2]);//获取文件名称
		fp=fopen(filename,"r");//以只读方式打开文件
		if(fp==NULL){//如果打不开
			printf("myshell: test: file named %s doesn't exist\n",filename);//文件不存在
		}
		else{//如果文件存在
			stat(filename,&buf);//储存相关信息到buf
			mode=buf.st_mode;
			if(strcmp(cmd_array[1],"-l")==0){//如果是符号链接(symbolic link)
				mode=mode&S_IFLNK;//位与操作
				if(mode==S_IFLNK){//检查得到的新值和S_IFLNK是否匹配
					printf("yes,this is a symbolic link\n");
				}
				else{
					printf("no,this is NOT a symbolic link\n");					
				}				
			}
			else if(strcmp(cmd_array[1],"-b")==0){//检查是不是块设备(block device)
				mode=mode&S_IFBLK;//位与操作
				if(mode==S_IFBLK){//检查与S_IFBLK是否匹配
					printf("yes,this is a block device\n");
				}
				else{
					printf("no,this is NOT a block device\n");					
				}
			}
			else if(strcmp(cmd_array[1],"-c")==0){//检查是不是字符设备(character device)
				mode=mode&S_IFCHR;//位与操作
				if(mode==S_IFCHR){//检查与S_IFCHR是否匹配
					printf("yes,this is a character device\n");
				}
				else{
					printf("no,this is NOT a character device\n");					
				}			
			}
			else if(strcmp(cmd_array[1],"-d")==0){//检查是不是目录文件(directory)
				mode=mode&S_IFDIR;//位与操作
				if(mode==S_IFDIR){//判断是不是和S_IFDIR匹配
					printf("yes,this is a directory\n");
				}
				else{
					printf("no,this is NOT a directory\n");					
				}			
			}
			else{//其他的非法输入
				printf("myshell: test: only 4 options are allowed:\n");
				printf("[-l],[-b],[-c],[-d]\n");
				printf("for more information: use 'help test'\n");
			}
		}
	}
}

void myumask(){
	int bit1,bit2,bit3,bitsum;
	mode_t new_umask,old_umask;
	if(cmd_cnt==1){//只用一个umask可以查看默认值
		printf("myshell: default umask value: %o\n",2);	
		return;
	}
	if(strlen(cmd_array[1])!=4||cmd_array[1][0]!='0'){//对于不正确的格式打印提示信息
		printf("myshell: umask: the format is umask 0[digit1][digit2][digit3], eg., umask 0002\n");
		return;
	}
	else{//获取每一位的值(用来得到最终的umask)
		switch(cmd_array[1][1]){
		case'0':
			bit1=0000;
			break;
		case'1':
			bit1=0100;
			break;
		case'2':
			bit1=0200;
			break;
		case'3':
			bit1=0300;
			break;
		case'4':
			bit1=0400;
			break;
		case'5':
			bit1=0500;
			break;
		case'6':
			bit1=0600;
			break;
		case'7':
			bit1=0700;
			break;
		default:
			printf("myshell: umask: out of range\n");
			break;
			}
		switch(cmd_array[1][2]){
		case'0':
			bit2=0000;
			break;
		case'1':
			bit2=0010;
			break;
		case'2':
			bit2=0020;
			break;
		case'3':
			bit2=0030;
			break;
		case'4':
			bit2=0040;
			break;
		case'5':
			bit2=0050;
			break;
		case'6':
			bit2=0060;
			break;
		case'7':
			bit2=0070;
			break;
		default:
			printf("myshell: umask: out of range\n");
			break;
			}
		switch(cmd_array[1][3]){
		case'0':
			bit3=0000;
			break;
		case'1':
			bit3=0001;
			break;
		case'2':
			bit3=0002;
			break;
		case'3':
			bit3=0003;
			break;
		case'4':
			bit3=0004;
			break;
		case'5':
			bit3=0005;
			break;
		case'6':
			bit3=0006;
			break;
		case'7':
			bit3=0007;
			break;
		default:
			printf("myshell: umask: out of range\n");
			break;
			}
		bitsum=bit1+bit2+bit3;
		new_umask=bitsum;//新的umask是这三个值的和
		printf("sum:%o\n",bitsum);
		old_umask=umask(new_umask);//这个函数返回旧的umask值
	}
	printf("myshell: umask changed successfully\n");
	printf("myshell: old value: %o\n",old_umask);//打印旧的值
	printf("myshell: new value: %o\n",new_umask);//打印当前的新值
}

void myjobs(){
	//可以使用ps命令来实现查看进程
	pid_t pid;
	pid=fork();//必须fork,否则会出现myshell退出这种奇怪的bug
	if(pid<0){
		perror("myshell: fork");
	}
	else if(pid==0){//子进程
		if(cmd_cnt>1){
			printf("myshell: jobs: incorrect use of jobs\n");
		}
		else{
			execlp("ps","ps","ax",NULL);//使用ps
		}
	}
	else{//父进程
		waitpid(pid,NULL,0);
	}
}

自定义的3个头文件:

file_isexist.h

/*
    测试一个文件是否存在
*/
#ifndef _COMMAND_FILE_ISEXIST_H_
#define _COMMAND_FILE_ISEXIST_H_

#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

/*
    函数功能:
        判断文件(目录)是否存在
    返回值:
        ==  0   不存在
        ==  1   存在
*/
int 
file_isexist(const char *filename /*需要测试是否存在的文件名*/ )
{
    assert(filename != NULL && filename[0] != 0);

    if(access(filename, R_OK) < 0)
        return 0;

    return 1;
}

/*
    函数功能:
        判断文件是否存在,并且是普通文件
    返回值:
        ==  0   不存在
        ==  1   存在
*/
int 
file_isreg(const char *filename /*需要测试是否存在的文件名*/ )
{
    assert(filename != NULL && filename[0] != 0);
    struct stat             statbuf;
    
    if(access(filename, R_OK) < 0)
        return 0;

    if(lstat(filename, &statbuf) == -1)
        return 0;

    if(S_ISREG(statbuf.st_mode))
        return 1;

    return 0;
}

/*
    函数功能:
        判断文件是否存在,并且是目录
    返回值:
        ==  0   不存在
        ==  1   存在
*/
int 
file_isdir(const char *filename /*需要测试是否存在的文件名*/ )
{
    assert(filename != NULL && filename[0] != 0);
    struct stat             statbuf;
    
    if(access(filename, R_OK) < 0)
        return 0;

    if(lstat(filename, &statbuf) == -1)
        return 0;

    if(S_ISDIR(statbuf.st_mode))
        return 1;

    return 0;
}

/*
    得到文件大小
    返回值:
    <   0     出错
    >=  0     文件大小
*/
int
get_file_size(int fd)
{
    struct stat         sta;

    if(fstat(fd, &sta) < 0){
        fprintf(stderr, 
            "get file size error [%s]\n",
            strerror(errno));
        return -1;
    }

    return sta.st_size;
}

#endif

err_msg.h

#ifndef _ERR_MSG_H_
#define _ERR_MSG_H_

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>


void
pr_msg(const char *fmt, ... )
{
    va_list                 va;

    va_start(va, fmt);
    vfprintf(stderr, fmt, va);
    fflush(stderr);
    va_end(va);
}

/*
    FIXME:
        这里看起来可能调pr_msg的,但这个可变参数我还不清楚具体去调用
*/
void
pr_msg2exit(const int exit_status, const char *fmt, ... )
{
    va_list                 va;

    va_start(va, fmt);
    vfprintf(stderr, fmt, va);
    fflush(stderr);
    va_end(va);

    exit(exit_status);
}

void
pr_errno_msg(const int err_no)
{
    if(err_no > 0)
    {
        fprintf(stderr,
                "%s\n", strerror(err_no));
        fflush(stderr);
    }
}

void
pr_errno_msg2exit(const int err_no)
{
    pr_errno_msg(err_no);

    exit(err_no);
}

#endif

command_comm.h

/*
    在写linux下命令时,大部份程序会用到的一些参数
*/
#ifndef _COMMAND_COMM_H_
#define _COMMAND_COMM_H_
#include <stdio.h>

#define EXIT_SUCESS             0           /* 正常退出状态         */
#define EXIT_FAILURE            1           /* 非正常退出状态       */
#define MAX_LINE_BUF_SIZE       1024        /* 默认的行缓冲大小     */

static char    *program_name = NULL;        /* 程序名               */
static int     exit_status = EXIT_FAILURE;  /* 程序退出状态         */
#endif
/*
    在写linux下命令时,大部份程序会用到的一些参数
*/
#ifndef _COMMAND_COMM_H_
#define _COMMAND_COMM_H_
#include <stdio.h>

#define EXIT_SUCESS             0           /* 正常退出状态         */
#define EXIT_FAILURE            1           /* 非正常退出状态       */
#define MAX_LINE_BUF_SIZE       1024        /* 默认的行缓冲大小     */

static char    *program_name = NULL;        /* 程序名               */
static int     exit_status = EXIT_FAILURE;  /* 程序退出状态         */

#endif




  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值