专栏首页技术栈大杂烩Linux:system 调用引发的 getcwd 异常

Linux:system 调用引发的 getcwd 异常

背景

幸福的生活总是相似的,天降的大锅各有各不同。

我们有个功能是这样的:有个以 root 运行的 python 程序,它需要以 test 用户执行 linux 命令,所以就通过 subprocess 库 + sudo 来执行,也就是下面的关系图:

./test_b 就是这么一个很简单的需求,本来是没有什么太大的问题的,然而事实总是喜欢打我们脸。

就输出下面的错误了:

虽然上面的错误不会影响程序的运行,但是处女座没法忍,一定要干干净净,明明白白!

错误定位

凭借过硬的英语水平,我们明白这个报错是因为访问不到父目录导致 getcwd 出错了。

聪明的童鞋一想就觉得是不是和上面的删除目录有关系,这时候肯定得看看 test_b 是什么内容,说不定能解决我们的疑问:

#!/usr/bin/python
import time
import os

time.sleep(3)
os.system('sleep 1')

那么问题来了,test_b 明明就只想睡个觉,不想涉足江湖事,也没有调用getcwd,为什么会输出这个报错咧!

在我们毫无头绪时,可以去喝喝快乐肥宅水,说不定就能脉动回来。

因为我就是这样看到找到线索了:shell-init

凭借过硬的英语水平,我们可以看到这个错误应该在 shell 初始化时候报的,这样很明显啦,去搜 bash 代码。

很快我们就找到这句错误定义的地方了:

root@bash-4.4 $ grep  'shell-init' -r *
variables.c:      temp_string = get_working_directory ("shell-init");

看到 get_working_directory 这个函数名这么正规,感觉这事靠谱了,顺着看看内容:

// builtins/common.c
char *
get_working_directory (for_whom)
     char *for_whom;
{
    ... (跳过)
    if (the_current_working_directory == 0)
    {
      fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
           (for_whom && *for_whom) ? for_whom : get_name_for_error (),
           _(bash_getcwd_errstr), strerror (errno));
      return (char *)NULL;
    }
    ... (跳过)
}

虽然大部分是通过变量传值进去,但是还是能看出就是咱们那句报错的原型了,

其实上面的代码实现并不是最关键的,关键的是,这些代码文件是在 bash 里面的,为什么system 会和bash 扯上关系呢?难道 system 还需要撸一发 shell 么,崩溃!我心目中的 system 不是这么随便的!

System 源码

带着不甘心去搜它的实现:

int system(const char * cmdstring)
{
    pid_t pid;
    int status;
    
    if(cmdstring == NULL){ 
         return (1);
    }
    
    if((pid = fork())<0){
         status = -1;
    }
    else if(pid = 0){

        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);

        exit(127); //子进程正常执行则不会执行此语句

    }
    else{
        while(waitpid(pid, &status, 0) < 0){
            if(errno != EINTER){
                status = -1;
                break;
            }
        }
    }
    return status;
}

它的出厂设置就是这样,原来是我一直没去深入了解它。

那现在其实一目了然了,system调用了 /bin/sh, 触发shell 初始化了, 在初始化变量时候调用了 get_working_directory,因为获取父目录失败了,所以输出了那段错误。

既然我们知道错误是 system 输出的,那么我们换个方式就应该能规避咯?

于是乎,./test_b 代码改成这样就不报错了:

#!/usr/bin/python
import time
import os

time.sleep(3)
# os.system('sleep')
os.execl('/bin/sleep', 'sleep', '1')

那么这里又引出了一个问题了

system 和 execl 都能执行系统命令,那两者有什么区别呢?

答案在上面的 system 的源码已经给出 80% 了,他们的区别就是:

system = fork + execl + waitpid

execl 只是系统 exec 族函数的其中一个,说到 exec 族函数,它们是将新的程序内容替换当前进程内容运行,具体大家可以去谷歌看看,这边就不多说了~

我们对 system 的实现已经有一定熟悉了,在后面使用这个方法时候,不管是在资源使用还是问题排查,都应该多一些意识,眼不见不代表没关系~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python爬虫: CU shell 板块

    身为运维岗的小屌丝, 对于shell, 甚至文本三剑客, 总是不可分割的, 因为工作上, 特别是日志处理查找等, 更能体现出三剑客的强大功力. 虽然说教程网上都...

    Lin_R
  • Python locals() 的陷阱

    在工作中, 有时候会遇到一种情况: 动态地进行变量赋值, 不管是局部变量还是全局变量, 在我们绞尽脑汁的时候, Python已经为我们解决了这个问题.

    Lin_R
  • Python: 浅析列表的变长变短

    Python 的列表(list)是一个非常灵活的数组,可以随意调整长度。正是因为这种便利,使得我们会情不自禁地去修改数组以满足我们的需求,其中相比于insert...

    Lin_R
  • EOS技术研究:合约与数据库交互

    文彬
  • Django——邮件发送

    EMAIL_HOST = 'smtp.qq.com' #不同的邮箱有不同的发件地址(收件地址)

    py3study
  • 【版本升级】实时音视频TRTC小程序解决方案升级

    视频通话场景常用于 1v1 视频客服、在线问诊等需要面对面视频沟通的场景,这些原本需要客户安装 App 才能解决的问题,现在只需要使用微信小程序也能轻松搞定了。

    shixin
  • 小程序音视频解决方案升级详情

    小程序音视频解决方案推出 <trtc-room> 组件,为了能更好的支持在线实时音视频功能,我们针对多种细分场景进行了深度优化,主要包括: _ 视频通话 _ ...

    腾讯云视频
  • 数读11.11丨网购下单最快4分钟送达,京东物流创新服务让消费者轻松收快递

    11.11京东全球好物节如火如荼,消费者摩拳擦掌,在集中的打折和促销中享受购物盛宴。而对物流来说,订单量的再度暴增,也带来又一场服务能力的集中展示和深度检验。

    京东技术
  • Scala基础——Map(映射)

    Scala映射(Map)是一组键/值对的对象。键在映射中是唯一的,但值不一定是唯一的。映射也称为哈希表。映射有两种,不可变的和可变的。默认情况下,Scala使用...

    羊羽shine
  • Python标准库05 存储对象 (pickle包,cPickle包)

    在之前对Python对象的介绍中 (面向对象的基本概念,面向对象的进一步拓展),我提到过Python“一切皆对象”的哲学,在Python中,无论是变量还是函数,...

    Vamei

扫码关注云+社区

领取腾讯云代金券