加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

shell – 我可以创建自己的输出流,它不同于stdout和stderr吗?

发布时间:2020-12-16 01:48:24 所属栏目:安全 来源:网络整理
导读:unistd.h的UNIX手册页说明: The following symbolic constants are defined for file streams:STDIN_FILENO File number of stdin. It is 0.STDOUT_FILENO File number of stdout. It is 1.STDERR_FILENO File number of stderr. It is 2. 抓住我的所有头文
unistd.h的UNIX手册页说明:

The following symbolic constants are defined for file streams:
STDIN_FILENO  File number of stdin.  It is 0.
STDOUT_FILENO File number of stdout. It is 1.
STDERR_FILENO File number of stderr. It is 2.

抓住我的所有头文件,我发现这是真的.

[/usr]grep -r "STDIN_FILENO" include
include/unistd.h:#define    STDIN_FILENO    0   /* Standard input.  */

[/usr] grep -r "STDOUT_FILENO" include 
include/unistd.h:#define    STDOUT_FILENO   1   /* Standard output.  */

[/usr]grep -r "STDERR_FILENO" include
include/boost/asio/detail/impl/handler_tracking.ipp:  ::write(STDERR_FILENO,line,length);
include/unistd.h:#define    STDERR_FILENO   2   /* Standard error output.  */

即使它们被定义,它们似乎永远不会被我的机器上的任何其他std头文件使用.我觉得很奇怪.也许0,1和2在别处使用而不是定义的宏.这些宏只是作为流的配置指示而引用.?

无论如何,我们可以通过这样做捕获shell中的特定输出流:

./program 1> stdout.txt
./program 2> stderr.txt
./program > both.txt 2>&1

我想创建自己的输出流,并通过这样做捕获它:

./program 3> mine.txt

我尝试搜索unistd.h和< iostream>所包含的其他文件.看看std :: cout和std :: cerr是如何工作的,但正如你可能想象的那样,我迷失了方向.

我更感兴趣的是你是否可以做到这一点,而不是它是否是一个好主意.

解决方法

子进程继承了打开的文件描述符.操作系统负责将进程与三个标准流连接,但您可以自由地执行任意数量的 open(),然后是 exec()(最好是在之前的 fork()之后).然后,孩子可以扫描打开的文件描述符列表(在/ proc / self / fd /中)或以某种方式“知道”使用哪些描述符.

这是一个用C编写的小例子.

#include <errno.h>   /* errno                        */
#include <stdio.h>   /* atoi,fprintf                */
#include <stdlib.h>  /* EXIT_SUCCESS,EXIT_FAILURE   */
#include <string.h>  /* strerror,strlen             */
#include <unistd.h>  /* write                        */

static const char *const message = "hello,worldn";

int main(int argc,char * * argv)
{
  int fd;
  int i;
  for (i = 1; i < argc; ++i)
    {
      fd = atoi(argv[i]);
      if (write(fd,message,strlen(message)) < 0)
        {
          fprintf(stderr,"error: cannot write to fd %d: %sn",fd,strerror(errno));
          return EXIT_FAILURE;
        }
    }
  return EXIT_SUCCESS;
}

程序的调用者负责打开程序应该写入的任何文件描述符,并通过其命令行参数告诉它.

为了传递连接到文件redir的打开文件描述符3,我们可以使用shell的exec实用程序打开文件描述符并执行子代.

$exec 3>redir ./a.out 3

这将在子进程退出后关闭当前shell,因此您可能希望在子shell中尝试它:

$sh -c 'exec 3>redir ./a.out 3'

或者,也可以不使用exec,而是使用重定向语法@ bmargulies.在这里,我们写入标准错误输出(2),以及文件描述符3和4,我们将3重定向到标准输出(1)和4重定向到文件redir.

$./a.out 2 3 4 3>&1 4>redir
hello,world
hello,world
$cat redir
hello,world

这种文件描述符的继承在服务器进程中大量使用,这些服务器进程允许其(非特权的)子进程拥有文件描述符来记录文件,chroot() jail之外的文件,TCP连接等等.

不幸的是,在exec()unt子进程之前忘记关闭文件描述符是一个常见的错误,可能与安全相关.有一个Valgrind模块来检查这个.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读