进程:程序的执行实例被称为进程。
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是一样的
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,返回第一次查找到的位置
******************************************************/