c 进程和系统调用
这一篇博客讲解进程和系统调用相关的知识
有这样一个场景,我需要输入一串文字,然后把我输入的文字加上一个本地的时间戳 保存在一个文件中,可以初步理解为一个备忘录也行
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 /** 6 * 获取一个当前时间 7 */ 8 char *now() { 9 time_t t; 10 time(&t); 11 return asctime(localtime(&t)); 12 } 13 14 int main(int argc, const char * argv[]) { 15 16 char comment[80]; 17 char cmd[120]; 18 19 fgets(comment, 80, stdin); 20 // sprintf 把内容写进一个变量中 21 sprintf(cmd, "echo '%s %s' >> reports.log",comment,now()); 22 // 调用系统的方法来执行这段命令 23 system(cmd); 24 return 0; 25 }
程序运行的结果是生成了一个文件
但有时候systemt() 函数也会是不安全的
sprintf(cmd, "echo ''&& ls / && echo' %s' >> reports.log",now());
修改上边的代码,然后会得到这样的结果
列出了根目录下的内容,因此可以使用命令删除文件或启动病毒
那么现在有一个场景,我们有exec来获取本机的网络配置,在Linux 和 Mac 上 你可以用一个叫/sbin/ifconfig的程序 在window上你用ipconfig
看代码
1 #include <stdio.h> 2 #include <errno.h> 3 #include <unistd.h> 4 #include <string.h> 5 6 int main(int argc, const char * argv[]) { 7 8 if (execl("/sbin/ifconfig", "/sbin/ifconfig",NULL) == -1) { 9 10 if (execlp("ipconfig", "ipconfig",NULL) == -1) { 11 12 fprintf(stderr, "Can not run ipconfig : %s",strerror(errno)); 13 } 14 } 15 return 0; 16 }
下边的代码也是很有意思的,可以充分说明exec函数的作用是停止当前进程 跳到另一个进程的
我们先创建一个叫做coffee.c 的文件,代码如下
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main(int argc, char* argv[]) { 5 6 char *w = getenv("EXTRA"); 7 if (!w) { 8 w = getenv("FOOD"); 9 } 10 if (!w) { 11 w = argv[argc - 1]; 12 } 13 14 char *c = getenv("EXTRA"); 15 if (!c) { 16 c = argv[argc - 1]; 17 } 18 19 printf("%s with %s \n", c, w); 20 return 0; 21 }
该程序的作用是先检测是否有环境变量EXTRA 没有就检测FOOD 如果还没有就给w赋值为最后一个参数值
先检测环境变量EXTRA 如果没有就给c赋值为最后一个参数
下边的代码可以检测我们上边这段代码是不是能够正确运行,首先我们新建一个coffeeTest.c的文件
1 #include <stdio.h> 2 #include <string.h> 3 #include <errno.h> 4 #include <unistd.h> 5 6 int main(int argc, char* argv[]) { 7 8 char *my_env[] = {"FOOD=Hanbaobao", NULL}; 9 if (execle("./coffee", "./coffee", "abv", NULL, my_env) == -1) { 10 fprintf(stderr, "Can not run process: %s",strerror(errno)); 11 return 1; 12 } 13 return 0; 14 }
gcc coffee.c -o coffee gcc coffeeTest.c -o coffeeTest ./coffeeTest
得到的结果是
abv with Hanbaobao
假如我们吧coffeeTest.c中的代码改成这样呢
1 if (execl("./coffee", "./coffee", "abv", NULL) == -1) { 2 fprintf(stderr, "Can not run process: %s",strerror(errno)); 3 return 1; 4 }
不出意外结果就是
abv with abv
好了,我们已经了解exec函数的使用方法了,其实exec函数算是程序中的最后一行代码了,只要调用它之后,程序立即停止运行,原理就是停止当前进程开启另外一个进程
那么如果我们还想要后边的代码继续执行呢
先看个例子
1 #include <stdio.h> 2 #include <string.h> 3 #include <errno.h> 4 #include <unistd.h> 5 6 int main(int argc, char* argv[]) { 7 8 char *my_env[] = {"FOOD=Hanbaobao", NULL}; 9 10 for (int i = 0; i < 3; i++) { 11 12 pid_t pid = fork(); 13 14 if (pid == -1) { 15 fprintf(stderr, "Can not fork process: %s",strerror(errno)); 16 return 1; 17 } 18 19 if (!pid) { 20 21 if (execle("./coffee", "./coffee", "abv", NULL, my_env) == -1) { 22 fprintf(stderr, "Can not run process: %s",strerror(errno)); 23 return 1; 24 } 25 } 26 27 28 } 29 return 0; 30 }
如果不加fork() 上边的程序只会打印一次结果,当循环中第一次调用exec的时候,后边的代码就不会再调用了
fork 是什么,看下边的解释