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 
", 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 是什么,看下边的解释

原文地址:https://www.cnblogs.com/machao/p/5633793.html