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

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

2014-10-10 20:23 477 查看
进程:程序的执行实例被称为进程。

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,返回第一次查找到的位置
******************************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: