天天看點

linux之fork()程序,程序替換建立新程序僵屍程序exec系列程序替換

建立新程序

我們可以通過系統調用來建立一個新的程序。這個系統調用完美的複制了目前程序,并且在程序表中建立了一個新的表項,新表項有很多屬性與目前項目是相同的。新的程序與原來的程序幾乎一模一樣,執行的代碼也是完全相同的。但是新的程序有自己的空間環境和檔案描述符等。

linux之fork()程式,程式替換建立新程式僵屍程式exec系列程式替換

從上面這幅圖我們可以看清,由fork産生的子程序傳回的值為0而原程序傳回一個新的pid。下面我們簡單示範一個fork作用。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
	pid_t  pid = fork();
	int n = 0;
	if (pid == 0)
	{
		//子程序執行
		n = 5;
		printf("this is children\n");
		sleep(1);
	}
	else
	{
		//父程序執行
		n = 3;
		printf("this is father\n");
		sleep(1);
	}
	for (int i = 0; i < n; i++){
		pirntf("yes\n");
		sleep(1);
	}
	exit(0);
}
           

僵屍程序

![在這裡插入圖檔描述](https://img-blog.csdnimg.cn/20191012151416710.png

linux之fork()程式,程式替換建立新程式僵屍程式exec系列程式替換

如果我們把上訴代碼做一個修改,我們就能看到僵屍程序如下

if (pid == 0)
	{
		//子程序執行
		n = 3;
		printf("this is children\n");
		sleep(1);
	}
	else
	{
		//父程序執行
		n = 5;
		printf("this is father\n");
		sleep(1);
	}
           

上訴代碼中,子程序先與父程序結束了,父程序沒擷取到子程序的推出碼,是以程序變成了一個僵屍程序。

linux之fork()程式,程式替換建立新程式僵屍程式exec系列程式替換

上圖中我們就可以看到這個僵屍程序。為了解決這個問題,我們采用一種方法,就是調用wait函數來擷取子程序的推出碼。

exec系列程序替換

linux之fork()程式,程式替換建立新程式僵屍程式exec系列程式替換

exec系列有如下幾個函數構成

================================================================*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>

int main(int argc, char * argv[], char *envp[]){
    printf("pid = %d \n", getpid());
    //char *myargv[10] = {"ps","-f"};
    //char *myenvp[10] = {"MYSTR=hello", "VAL=100"};
    //execl("/bin/ps", "ps", "-f", (char*)0);
    //execlp("ps", "ps", "-f", (char*)0);
    //execle("bin/ps", "ps", "-f", (char*)0,myenvp);
    //execv("/bin/ps", myargv);
    //execvp("ps", myargv);
    execl("./main", "main", "hello", "123", (char *)0);
    perror("execl error");
    exit(0);
}
           

利用這個函數,我們就可以完成一個簡單的linux下的bash指令。

具體代碼如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<pwd.h>
#define MAX_NUM 10
#define PATH "/home/ma/01-圖論c++/02-linux學習/08-fork等程序/mybin/"

void PrintInfo(){
    int uid = getuid(); 
    char *s = "$";
    if (uid == 0){
        s = "#";
    }
    struct passwd *ptr = getpwuid(uid);
    if (ptr == NULL){
        printf("mybash>>$");
        fflush(stdout);
        return;
    }
    char hostname[128] = {0};
    if (gethostname(hostname, 128) == -1){
        printf("myabsh>>$");
        fflush(stdout);
        return;
    }
    char dir[256] = {0};
    getcwd(dir, 256);
    char *last_p = "/";
    char *cur_p = strtok(dir, "/");
    while(cur_p != NULL ){
        last_p = cur_p;
        cur_p = strtok(NULL, "/");
    }
    char *host_name = strtok(hostname, ".");
    printf("[%s@%s %s]%s ", ptr->pw_name,host_name, last_p, s);
    fflush(stdout);
}

int main(int argc, char *argv[]){
    while(1){
        PrintInfo();
        char buf[128] = {0};
        fgets(buf, 128, stdin);
        buf[strlen(buf)-1] = 0;
        int i = 0;
        char *myargv[MAX_NUM] = {0};
        char *s = strtok(buf, " ");
        while(s != NULL){
            myargv[i] = s;
            i++;
            s = strtok(NULL, " ");
        }


        if (myargv[0] == NULL){
            continue;
        }else if(strcmp(myargv[0], "cd") == 0){
            if (myargv[1] != NULL){
                if( chdir(myargv[1]) == -1){
                    perror("cd error");
                }
            } 
            continue;
        }else if (strcmp(myargv[0], "exit") == 0){
            exit(0);
        }

        pid_t pid = fork();
        assert(pid != -1);
        if (pid == 0){
            //execvp(myargv[0], myargv);
            char path[256] = {0};
            if (strncmp(myargv[0], "/", 1) != 0 && strncmp(myargv[0], "./", 2) != 0){
                strcpy(path, PATH);
            }
            strcat(path, myargv[0]) ;
            execv(path, myargv);
            perror("exec error");
            exit(0);
        }
        wait();
    }
}