linux 系统编程-学习笔记7-进程/fork/vfork/exec函数族

进程:程序的执行实例被称为进程。

u-boot ==>Image ==>根文件系统==>init进程(1)

==>exec执行进程==>启动代码==>main{==>传入环境变量

exit/return ==>1)刷新缓冲区,2)关闭所有打开的文件描述符,3)调用清理函数 ==>系统
_exit/_Exit ==>系统
}
==================================================================================

进程的操作:
1.进程的创建
2.进程的执行
3.进程的退出

进程的几种状态:
1.等待/就绪态
2.运行态
3.终止态
4.僵尸态


===================================================================================
创建一个新的进程:
pid_t fork(void); (pid_t -->int)
fork之后会有两个返回值:
 > 0 : 返回的值是新建子进程的ID==>返回给父进程
 = 0 : 返回的是子进程
 = -1: 错误
 
父进程fork一个子进程之后,子进程继承父进程的资源空间(几乎所有的)
==>之后,父,子进程自己拥有独立的资源空间
 ___________________________________________
 typedef __kernel_pid_t pid_t;`
 typedef int __kernel_pid_t;
 ___________________________________________
 
pid_t getpid(void);
:获取本进程的进程ID
pid_t getppid(void);
:过去本进程的父进程ID



===============================================
进程间切换条件:
(子进程切换到父进程)
1.时间片结束
2.子进程执行结束
3.子进程被阻塞
4.子进程被中断
5.被优先级高(父进程)抢占

注意:保护现场(目的是能切换回来)

====================================================

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
功能:等待子进程返回,子进程返回的状态保存在变量status中,如果不关系则填NULL,
      wait返回所等待的子进程的进程ID
注意:如果父进程不调用wait/waitpid等待子进程返回,回收其资源,则该子进程变成僵尸进程


僵尸进程:进程结束之后,其所占用的资源没有被释放,则称之为僵尸进程
___________________________________________________________________

通过status中的值可以判断子进程退出的状态:
WIFEXITED(status)
正常返回,返回的值由子进程中exit/_exit/return返回的值确定
WEXITSTATUS(status)
:获取返回的值


WIFSIGNALED(status)
:被信号打断
WTERMSIG(status)
:获取到打断该子进程的信号

==============================================================
pid_t waitpid(pid_t pid, int *status, int options);

waitpid(-1, &status, 0);//功能和wait是一样的




pid_t vfork(void);
1.功能同fork几乎一样

相同点:
1.功能同fork一样,创建一个新的进程
2.vfork之后会有两个返回值:
 > 0 : 返回的值是新建子进程的ID==>返回给父进程
 = 0 : 返回的是子进程
 = -1: 错误

 ___________________________________________
不同点:
1.fork : 父进程fork一个子进程之后,子进程继承父进程的资源空间(几乎所有的)
==>之后,父,子进程自己拥有独立的资源空间
  vfork:父,子进程共享资源空间

2.fork :父,子进程谁先运行,由内核确定
  vfork: 保证子进程先运行
==>调用exec执行进程
==>所以只有调用exit退出子进程之后父进程才能执行
================================================================================

exec函数族:
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);


l:表示跟上一系列的参数
p:表示可以自动的去匹配路径,不给必绝对路径
e:表示可以传入环境变量参数数组
v:表示所有的参数可以通过数组传递

path/file: 命令 (绝对路径/相对路径)
arg      : 参数列表

===========================================================================================
前面的五个exec函数族都是由execve封装而来的,真正的系统调用是execve
int execve(const char *filename, char *const argv[],
                  char *const envp[]);

filname : 文件命名/命令
argv    : 命令参数选项的字符串数组
envp    : 环境变量数组


/*练习:实现一个简单的shell终端.*/

#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <shadow.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

struct user
{
	char username[100];		//用户名
	char psd[100];			//原始密码
	char salt[100];			//密码种子
	char cmd[1024];			//命令
};

struct user user;

int login(void);
void show_shell(void);
void get_commond(void);
void do_commond(void);

int main(int argc, char *argv[])
{
	/*用户登录*/
	if(-1 == login())
	{
		printf("\nlogin faild .......\n");
		return -1;
	}

	while(1)
	{
		show_shell();	//显示shell终端
		get_commond();	//获取命令
		do_commond();	//处理命令
	}


	return 0;
}

/********************************************
 *功能:判断用户名和密码是否匹配
 *返回值:
 *  匹配:返回0
 *  错误:返回-1
 * *****************************************/
int login(void)
{
	int ret;
	struct passwd *pw = NULL;
	struct spwd *sp = NULL;
	char *dol = NULL;
	char *pssd = NULL;
	
	system("clear");

	/*输入用户名*/
	write(1,"username : ",strlen("username : "));
	ret= read(0,user.username,sizeof(user.username)-1);
	if(ret > 0)
	{
		user.username[ret-1] = '\0';
	}

	/*输入用户密码**/
	write(1,"passwd : ",strlen("passwd : "));

	system("stty -echo -raw");
	ret = read(0,user.psd,sizeof(user.psd));
	if(ret > 0)
	{
		user.psd[ret-1] = '\0';
	}
	system("stty echo");

	/*判断用户是否有密码*/
	pw = getpwnam(user.username);
	if(NULL == pw)
	{
		return -1;
	}
	if(strcmp(pw->pw_passwd,"x"))
	{
		//没有密码
		return -1;
	}
	
	/*获取用户加密密码*/
	sp = getspnam(user.username);
	if(NULL == sp)
	{
		return -1;
	}
	strcpy(user.salt,sp->sp_pwdp);
	
	dol = strrchr(user.salt,'$');
	if(NULL == dol)
	{
		return -1;
	}
	dol++;
	*dol = '\0';

	/*通过crypt进行密码加密*/
	pssd = (char *)crypt(user.psd,user.salt);
	if(NULL == pssd)
	{
		return -1;
	}

	if(strcmp(pssd,sp->sp_pwdp) == 0)
	{
		system("clear");
		printf("login success.....\n");
		sleep(2);
		return 0;
	}
	else
	{
		return -1;
	}
}

/*显示shell终端*/
void show_shell(void)
{
	char path[100] = {0};
	
	/*获取用户当前的绝对路径*/
	getcwd(path,99);	
	printf("%s@:%s&&& ",user.username,path);
	fflush(stdout);
}

/*获取命令*/
void get_commond(void)
{
	int ret;

	memset(user.cmd,0,sizeof(user.cmd));
	ret = read(0,user.cmd,sizeof(user.cmd));
	if(ret > 0)
	{
		user.cmd[ret-1] = '\0';
	}
}
/**前面的空格处理*/
void eat_white(char *str)
{
	int len;
	int i;

	i = 0;
	len = strlen(str);
	while(1)
	{
		if(isblank(str[i]))
		{
			i++;
		}
		else
		{
			 break;
		}
	}
	memmove((void *)&str[0],(void *)&str[i],len-i+1);
}

/*处理命令*/
void do_commond(void)
{
	pid_t pid;
	
	eat_white(user.cmd);
	if(strncmp(user.cmd,"exit",4) == 0)
	{
		exit(0);	//退出进程
	}
	else if(strncmp(user.cmd,"cd",2) == 0)
	{
		chdir(strchr(user.cmd,' ')+1);	//切换路径
	}
	else
	{
		pid = fork();
		if(0 == pid)
		{//子进程
			execlp("/bin/sh","sh","-c",user.cmd,NULL);
		}
		else if(pid > 0)
		{
			wait(NULL);	
		}
		else
		{
			perror("fork");
			exit(-1);
		}
	}
}


/******************************************************
  char *strchr(const char *s, int c);
  功能是从一个字符串的开头查找字符c,返回第一次查找到的位置
 ******************************************************/







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值