[转帖]exec系统调用

exec,系统,调用 · 浏览次数 : 0

小编点评

**进程的执行(exec)** **exec** 函数可以将新程序加载到调用进程的内存空间,并执行该程序。 **步骤:** 1. **准备新程序的路径名:** `pathname` 是指向新程序的路径名,相对路径或绝对路径都可以。 2. **创建子进程:** 使用 `fork` 创建子进程,并使用 `execve()` 将新程序加载到内存中。 3. **设置环境变量:** 使用 `envp` 传递给新程序的环境变量。 4. **执行新程序:** 使用 `execve()` 调用新程序的`pathname`。 **类型:** * **e类 execve:** 支持可变参数列表,可以使用 `stdarg` 系列 API进行处理。 * **l类 execlp:** 支持可变参数列表,可以使用 `stdarg` 系列 API进行处理。 * **f类 execvp:** 支持从文件描述符中指定程序名,可以使用 `stdarg` 系列 API进行处理。 **示例:** ```c++ #include #include int main() { // ... // 创建子进程 pid_t child_pid = fork(); if (child_pid == 0) { // 作为新程序执行 execl("/bin/bash", "bash", "-c", "my_script.sh", NULL); } // 等候子进程执行完成 wait(NULL); return 0; } ``` **注意:** * `exec()` 函数会丢弃现有的进程的文本段,包括堆栈段。 * 新程序的信号处理函数可能被丢弃,因此需要手动设置。

正文

https://www.jianshu.com/p/3bf14f7d889c

 

进程的执行(exec)

  • execve

    ececve系统调用可以将新程序加载到调用进程的内存空间,在这一过程中,将丢弃现有的进程的文本段,同时,进程的堆栈段,数据都会被新进程的相应部件所替换

    在执行完各种初始化代码之后(比如C++的构造函数),新的程序会从main处开始执行

    通常的使用方法是使用fork创建子进程,然后使用execve()执行新进程

    #include<unistd.h>
    int execve(const char*pathname, char *const argv[], char *const envp[])
                                                      //永远都是返回失败
    
    • 参数解析

      pathname:准备载入当前进程空间的新程序的路径名,相对或者绝对都可以

      argv:传递给新进程的命令行参数

      envp:新程序的环境列表,一般直接赋为environ

    • 进程id

      execve()调用之后,进程的ID依旧保持不变

    • 用户

      execve()调用后,会以进程的有效用户ID(effective-id)去覆盖保存用户ID(saved-id)

  • exec的各种xd

    #include<unistd.h>
    
    int execle(const char *pathname, const char *arg, ...,
              (char *)NULL, char *const envp[]);
    int execlp(const char *filename, const char *arg, ..., (char *) NULL);
    int execvp(const char* pathname, char *const argv[]);
    int execl(const char*pathname, const char *arg, ..., (char *)NULL);
                                                          //永远都是返回失败
    

    上面的...代表的是可变参数列表,即一个或多个参数,可以使用stdarg系列API进行解读

    这些系统调用可以分为3类

    1. e类

      execve,execle等,他们允许用户通过使用envp参数显式指定环境变量

    2. p类

      execlp,execvp等,他们只需要提供运行的程序名即可,系统会在环境变量PATH中来找

      如果pathname中包含'\',那么系统还是会将其视为路径名而不是文件名

    3. l类

      execlp,execl等,可以使用可变参数列表来指定参数

  • fexecve

    fexecve可以执行由文件描述符指定的程序,而不是通过路径名

    #include<unistd.h>
    int fexecve(int fd, char *const argv[], char *const envp[])
                                                      //永远返回失败
    

解释器脚本

上述系统调用其实不仅能够指定可执行文件,还能够指定脚本文件

拿shell举例:

在脚本文件的开头,往往会有着这么一行

#! /bin/bash  [附加参数]

这一行用来指定脚本文件的解释器,shell脚本当然就是指定bash了

  • 执行过程

    当使用exec()(指一系列系统调用)来运行脚本文件时,如果execve()检测到传入的文件以"#!"开头,那么他就会按照如下的参数列表来执行解释器程序

    解释器路径 [附加参数] 脚本文件路径 脚本文件参数
    

    其中脚本文件路径和脚本文件参数都是在函数的参数列表中给出的,前面的解释器路径,附加参数都是从脚本文件的首行得到的

    由上可以看出,附加参数是与解释器路径搭配使用的,比如指定/bin/bash为解释器,那么就可以使用-c,-i等参数

    注:execlp和execvp有些特殊,如果脚本文件首行没有指定解释器,那么他们会通过环境变量找到指定脚本文件后,会默认使用shell来解释

文件描述符与exec

默认情况下,有exec的调用程序所打开的所有文件描述符在exec的执行过程中会保持打开状态,且在新程序中仍然有效,这一特性确保了新执行的进程无需再次打开文件,十分有用

执行时关闭标志(FD_CLOEXEC)

从安全编程的角度出发,应该在加载新程序之前确保关闭那些不必要的文件描述符,打开文件时指定FD_CLOEXEC标志就可以做到这一点

如果设置了该标志,那么在执行exec系统调用时,会自动的关闭该文件,如果调用exec失败,那么文件描述符仍会保持打开状态

信号与exec

  • 信号处置

    调用exec时会丢弃进程的文本段,那么自然就会丢弃程序的信号处理函数,如果在调用之前对某一个信号的设置为SIG_IGN或者SIG_DFL,那么在执行exec调用后,这些信号的处置将不会改变,否则,信号处置统统都会被置为SIG_DFL

  • 掩码及等待队列

    在执行exec之后,进程的信号掩码以及pending信号的设置均得以保存

与[转帖]exec系统调用相似的内容:

[转帖]exec系统调用

https://www.jianshu.com/p/3bf14f7d889c 进程的执行(exec) execve ececve系统调用可以将新程序加载到调用进程的内存空间,在这一过程中,将丢弃现有的进程的文本段,同时,进程的堆栈段,数据都会被新进程的相应部件所替换 在执行完各种初始化代码之后(比如

[转帖]利用BCC Tools追踪指定PID进程的方法

http://t.zoukankan.com/Emuaer-p-EmuaBCCTools3.html 想法的产生 通过熟悉许多BCC tools后,我们可以通过一些工具的组合,来实现一些定向的进程追踪 execsnoop跟踪新进程创建,跟踪exec函数。 bashreadline打印系统中所有bas

[转帖]kubelet 原理解析五: exec的背后

https://segmentfault.com/a/1190000022163850 概述 线上排查pod 问题一般有两种方式,kubectl log或者kubectl exec调试。如果你的 log 写不够优雅,或者需要排除网络问题必须进容器,就只能 exec 了。 # 在pod 123456-

[转帖]Linux-find命令报错: missing argument to `-exec'

https://www.cnblogs.com/yeyuzhuanjia/p/17427143.html 报错提示:find: missing argument to `-exec' 今天写一个清理脚本,用到了find命令。本来是这么写的: find . -type f -mtime +7 -nam

[转帖]Linux 写时复制技术

https://www.cnblogs.com/dwtfukgv/p/15125933.html 目录 Linux fork Linux exec Linux 进程虚拟地址空间 栈 内存映射段 堆 BSS段 数据段 代码段 分段的优点 页表 写时复制原理 非写时复制fork一个子进程 写时复制for

[转帖]nsenter 工具的使用

一、背景 对于运行在后台的docker容器,我们经常需要做的事情是进入到容器中,docker为我们提供了docker exec 、docker attach 命令,并且还提供了nsenter工具,外部工具供我们使用。 docker attach存在的问题是:当多个窗口同时attach到同一个容器时,

[转帖]docker 开启2375端口,提供外部访问docker

https://www.cnblogs.com/rxysg/p/15816320.html 一、编辑docker文件:/usr/lib/systemd/system/docker.service 命令:vim /usr/lib/systemd/system/docker.service 修改Exec

[转帖]docker编译speccpu2017

实验步骤: 1.下载docker和speccpu2017 2.docker下载镜像,创建容器 3.将下载的宿主机speccpu2017拷贝到docker创建的容器中(docker cp) 4.在docker容器(docker exec)中编译运行speccpu2017 下载docker yum in

[转帖]

Linux ubuntu20.04 网络配置(图文教程) 因为我是刚装好的最小系统,所以很多东西都没有,在开始配置之前需要做下准备 环境准备 系统:ubuntu20.04网卡:双网卡 网卡一:供连接互联网使用网卡二:供连接内网使用(看情况,如果一张网卡足够,没必要做第二张网卡) 工具: net-to

[转帖]

https://cloud.tencent.com/developer/article/2168105?areaSource=104001.13&traceId=zcVNsKTUApF9rNJSkcCbB 前言 Redis作为高性能的内存数据库,在大数据量的情况下也会遇到性能瓶颈,日常开发中只有时刻