欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:運維 【Linux】進程替換

柚子快報激活碼778899分享:運維 【Linux】進程替換

http://yzkb.51969.com/

???個人主頁:秦jh__https://blog.csdn.net/qinjh_?spm=1010.2135.3001.5343??系列專欄:https://blog.csdn.net/qinjh_/category_12625432.html

目錄

進程程序替換

代碼和現(xiàn)象

替換函數(shù)?

?替換原理

函數(shù)解釋?

命名理解?

簡易shell?

前言

????? hello! 各位鐵子們大家好哇。

? ? ? ? ? ? ?今日更新了Linux的進程替換的內(nèi)容 ????? 歡迎大家關(guān)注?點贊?收藏??留言?

進程程序替換

代碼和現(xiàn)象

運行后,發(fā)現(xiàn)使用了ls命令,而且打印end的語句也不見了。

exec*函數(shù)的作用:讓進程通過exec*函數(shù)把全新的程序替換到自己對應(yīng)的代碼和數(shù)據(jù),然后執(zhí)行新的程序。

exec*函數(shù)執(zhí)行完畢后,后續(xù)的代碼不見了,因為被替換了。

替換函數(shù)?

其實有六種以exec開頭的函數(shù),統(tǒng)稱exec*函數(shù):

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[]);int execve(const char *path, char *const argv[], char *const envp[]);

?替換原理

我們自己的代碼編譯運行后就會變成可執(zhí)行程序,運行起來后就變成進程。

進程=內(nèi)核數(shù)據(jù)結(jié)構(gòu)+代碼和數(shù)據(jù)

替換的意義是:內(nèi)核數(shù)據(jù)結(jié)構(gòu)不變,個別屬性可能會變,用新程序的代碼代替老程序的代碼。?

進程的替換沒有創(chuàng)建新的進程!所以調(diào)用exec*前后該進程的id并未改變。

站在被替換進程的角度,本質(zhì)就是這個程序由磁盤被加載到內(nèi)存中了。(馮諾依曼體系)

函數(shù)解釋?

這些函數(shù)如果調(diào)用成功則加載新的程序從啟動代碼開始執(zhí)行,不再返回。如果調(diào)用出錯則返回-1所以exec*函數(shù)只有出錯的返回值而沒有成功的返回值。

?如上圖,沒有l(wèi)ss命令,所以替換會失敗。如果替換成功,就不會向后繼續(xù)運行。所以只要繼續(xù)運行了,就一定是替換失敗了。

1 #include

2 #include

3 #include

4 #include

5 #include

6

7 int main()

8 {

9 printf("testexec ... begin!\n");

10

11 pid_t id=fork();

12 if(id==0)

13 {

14 sleep(2);

15 //child

16 execl("/usr/bin/ls","ls","-l","-a",NULL);

17 exit(1);

18 }

19

20 //father

21 int status=0;

22 pid_t rid=waitpid(id,&status,0);

23 if(rid>0)

24 {

25 printf("father wait success,child exit code:%d\n",WEXITSTATUS(status));

26 }

27 printf("testexec ... end!\n");

28 return 0;

29 }

運行結(jié)果如上圖,?進程替換成功了,父進程也等待成功。上面是用fork創(chuàng)建子進程,讓子進程去替換,讓子進程完成任務(wù),而不改變父進程。這也是進程替換的重要意義。

命名理解?

l(list) : 表示參數(shù)采用列表v(vector) : 參數(shù)用數(shù)組p(path) : 有p自動搜索環(huán)境變量PATHe(env) : 表示自己維護環(huán)境變量?

以execl為例,path表示要執(zhí)行的程序的路徑。第二個是可變參數(shù),如果我們用ls命令,后面需要選項的話,就用逗號隔開。選項帶完后,后面必須加上NULL,這是格式要求。

上面的選項參數(shù)的隔開就是l(列表)的體現(xiàn)。

?execv的第一個參數(shù)跟上面的一樣。v就是vector的意思,所以參數(shù)二就是傳數(shù)組。

帶有p的就是 用戶可以不傳執(zhí)行文件的路徑(但是文件名稱要傳)。直接告訴exec*,我想執(zhí)行誰就行。有了p,系統(tǒng)會自動在環(huán)境變量PATH中進行查找。

?

?

注意上面的參數(shù)1表示我想執(zhí)行誰,參數(shù)2表示我想怎么執(zhí)行。?二者含義不一樣。

用一個可執(zhí)行程序替換另一個可執(zhí)行程序:?

當(dāng)我們想要通過make一下就能生成兩個可執(zhí)行程序,可以通過.PHONY設(shè)置一個為目標(biāo),把想要生成的可執(zhí)行文件作為依賴方法,這樣就能同時生成兩個了。

?

上面是通過一個程序替換另一個程序的例子。?

?有了這個例子的基礎(chǔ),接下來介紹execvpe

?mypragma.cc

1 #include

2 #include

3 using namespace std;

4

5 int main(int argc,char *argv[],char* env[])

6 {

7 int i=0;

8 for(;argv[i];i++)

9 {

10 printf("argv[%d]:%s\n",i,argv[i]);

11 }

12

13 printf("------------------------\n");

14 for(i=0;env[i];i++)

15 {

16 printf("env[%d]:%s\n",i,env[i]);

17 }

18 printf("------------------------\n");

19

20

21 cout<<"hello C++,I am a C++ pragma!"<

22 cout<<"hello C++,I am a C++ pragma!"<

23 cout<<"hello C++,I am a C++ pragma!"<

24 cout<<"hello C++,I am a C++ pragma!"<

25 return 0;

26 }

testexec.c?

7 int main()

8 {

9 printf("testexec ... begin!\n");

10

11 pid_t id=fork();

12 if(id==0)

13 {

14 char* const argv[]=

15 {

16 (char*)"mypragma",

17 NULL

18 };

19

20 char* const envp[]=

21 {

22 (char*)"HAHA=1111",

23 (char*)"HEHE=2222",

24 NULL

25 };

26 printf("child pid:%d\n",getpid());

27 sleep(2);

28 execvpe("./mypragma",argv,envp);

43 exit(1);

44 }

46 //father

47 int status=0;

48 pid_t rid=waitpid(id,&status,0);

49 if(rid>0)

50 {

51 printf("father wait success,child exit code:%d\n",WEXITSTATUS(status));

52 }

53 printf("testexec ... end!\n");

54 return 0;

55 }

編譯運行testexec.c程序后,就會用mypragma程序替換。里面的execvpe,參數(shù)1是要替換的文件名,參數(shù)2表示怎么執(zhí)行,參數(shù)3就是環(huán)境變量。參數(shù)2和參數(shù)3都會被傳到替換文件中。所以運行結(jié)果如下圖:

對于main函數(shù)的子進程,它的父進程main本身也是bash的子進程,所以可以通過環(huán)境變量的第三方指針extern char** environ 獲取系統(tǒng)的環(huán)境變量。

所以,參數(shù)3的意義就是整體替換所有的環(huán)境變量。

事實上,只有execve是真正的系統(tǒng)調(diào)用,其它五個函數(shù)最終都調(diào)用 execve,所以execve在man手冊 第2節(jié),其它函數(shù)在 man手冊第3節(jié)。?之所以弄那么多接口,主要是為了支持不同的應(yīng)用場景。

簡易shell?

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8

9 #define SIZE 512

10 #define ZERO '\0'

11 #define SEP " "

12 #define NUM 32

13 #define SkipPath(p) do{ p += (strlen(p)-1); while(*p != '/') p--; }while(0)

14

15

16 // 為了方便,我就直接定義了

17 char cwd[SIZE*2];

18 char *gArgv[NUM];

19 int lastcode = 0;

20

21 void Die()

22 {

23 exit(1);

24 }

25

26 const char *GetHome()

27 {

28 const char *home = getenv("HOME");

29 if(home == NULL) return "/";

30 return home;

31 }

32

33 const char *GetUserName()

34 {

35 const char *name = getenv("USER");

36 if(name == NULL) return "None";

37 return name;

38 }

39 const char *GetHostName()

40 {

41 const char *hostname = getenv("HOSTNAME");

42 if(hostname == NULL) return "None";

43 return hostname;

44 }

45 // 臨時

46 const char *GetCwd()

47 {

48 const char *cwd = getenv("PWD");

49 if(cwd == NULL) return "None";

50 return cwd;

51 }

52

53 // commandline : output

54 void MakeCommandLineAndPrint()

55 {

56 char line[SIZE];

57 const char *username = GetUserName();

58 const char *hostname = GetHostName();

59 const char *cwd = GetCwd();

60

61 SkipPath(cwd);

62 snprintf(line, sizeof(line), "[%s@%s %s]> ", username, hostname, strlen(cwd) == 1 ? "/" : cwd+1);

63 printf("%s", line);

64 fflush(stdout);

65 }

66

67 int GetUserCommand(char command[], size_t n)

68 {

69 char *s = fgets(command, n, stdin);

70 if(s == NULL) return -1;

71 command[strlen(command)-1] = ZERO;

72 return strlen(command);

73 }

74

75

76 void SplitCommand(char command[], size_t n)

77 {

78 (void)n;

79 // "ls -a -l -n" -> "ls" "-a" "-l" "-n"

80 gArgv[0] = strtok(command, SEP);

81 int index = 1;

82 while((gArgv[index++] = strtok(NULL, SEP))); // done, 故意寫成=,表示先賦值,在判斷. 分割之后,strtok會返回NULL,剛好讓gArgv最后一個元素是NULL, 并且while判斷結(jié)束

83 }

84

85 void ExecuteCommand()

86 {

87 pid_t id = fork();

88 if(id < 0) Die();

89 else if(id == 0)

90 {

91 // child

92 execvp(gArgv[0], gArgv);

93 exit(errno);

94 }

95 else

96 {

97 // fahter

98 int status = 0;

99 pid_t rid = waitpid(id, &status, 0);

100 if(rid > 0)

101 {

102 lastcode = WEXITSTATUS(status);

103 if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);

104 }

105 }

106 }

107

108 void Cd()

109 {

110 const char *path = gArgv[1];

111 if(path == NULL) path = GetHome();

112 // path 一定存在

113 chdir(path); //更改當(dāng)前的工作路徑

114

115 // 刷新環(huán)境變量

116 char temp[SIZE*2];//臨時緩沖區(qū)

117 getcwd(temp, sizeof(temp)); //得到當(dāng)前進程的絕對路徑

118 snprintf(cwd, sizeof(cwd), "PWD=%s", temp);//

119 putenv(cwd); // 導(dǎo)入新的環(huán)境變量

120 }

121

122 int CheckBuildin()

123 {

124 int yes = 0;

125 const char *enter_cmd = gArgv[0];

126 if(strcmp(enter_cmd, "cd") == 0)

127 {

128 yes = 1;

129 Cd();

130 }

131 else if(strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0)

132 {

133 yes = 1;

134 printf("%d\n", lastcode);

135 lastcode = 0;

136 }

137 return yes;

138 }

139

140

141 int main()

142 {

143 int quit = 0;

144 while(!quit)

145 {

146 // 1. 我們需要自己輸出一個命令行

147 MakeCommandLineAndPrint();

148

149 // 2. 獲取用戶命令字符串

150 char usercommand[SIZE];

151 int n = GetUserCommand(usercommand, sizeof(usercommand));

152 if(n <= 0) return 1;

153

154 // 3. 命令行字符串分割.

155 SplitCommand(usercommand, sizeof(usercommand));

156

157 // 4. 檢測命令是否是內(nèi)建命令

158 n = CheckBuildin();

159 if(n) continue;

160 // 5. 執(zhí)行命令

161 ExecuteCommand();

162 }

163 return 0;

164 }

柚子快報激活碼778899分享:運維 【Linux】進程替換

http://yzkb.51969.com/

精彩鏈接

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19569754.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機訪問

文章目錄