2015-10-21 73 views
5

如何从perl完成mount系统调用?以下:从perl执行mount系统调用

$ret = syscall(&SYS_mount, "/proc", "/path/to/my/mount/point", 0, 0, 0); 

结果:

Modification of a read-only value attempted at ... 

我不能把使用system,因为我需要做一个mount()系统调用的mount程序似乎并没有能够在mount程序。更具体地讲,我需要调用:

mount("/proc", "/path/to/my/mpoint/point", NULL, MS_REC|MS_PRIVATE|MS_BIND, NULL); 

但是,如果我尝试运行与非特权的非共享安装Linux的命名空间中的以下内容:

mount --make-rprivate --bind /proc /path/to/my/mountpoint 

然后我收到以下错误:

mount: wrong fs type, bad option, bad superblock on /proc, 
     missing codepage or helper program, or other error 

     In some cases useful info is found in syslog - try 
     dmesg | tail or so. 

使用strace表明mount程序实际上做的是调用:

mount("/proc", "/path/to/my/mountpoint", ..., MS_MGC_VAL|MS_BIND, NULL); 
mount("none", "/path/to/my/mointpoint", NULL, MS_REC|MS_PRIVATE, NULL); 

但是这种选项拆分不起作用。我需要MS_BINDMS_REC|MS_PRIVATE通过一次调用mount系统调用才能在非特权的非共享挂载名称空间中工作。

那么如何在perl中执行我的初始系统调用,而不会出现关于尝试修改只读值的错误消息?

编辑

值得庆幸的是池上很快尝试使用Perl的syscall功能时指出我做错了什么,但如果有人认为这对如何结合来自非特权安装座内安装的目录搜索时命名空间只是mount命令行实用程序,这里是如何:

mount --rbind /proc /path/to/my/mountpoint 

这反过来会调用内部的系统调用如下:

mount("proc", "/path/to/my/mountpoint", ..., MS_MGC_VAL|MS_BIND|MS_REC, 0); 

MS_MGC_VAL标志似乎是为了与2.4之前的内核版本向后兼容。重要的位是MS_BIND(用于执行绑定挂载本身)和MS_REC(用于递归地执行此操作,以使其内容被其他挂载隐藏的内容在其中完成的目录没有在挂载名称空间中公开其内容)。

所以现在我必须决定是否我去一个Perl system函数调用或只是做mount系统调用,因为两者的工作也很好:)

回答

8

syscall拒绝一个指针传递给一个恒定的字符串缓冲区因为它不知道参数是char *还是const char *

You can't use a string literal (or other read-only string) as an argument to syscall because Perl has to assume that any string pointer might be written through

解决方案很简单。只需将该常量先复制到变量中即可。

my $ret = syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0); 

测试:

$ perl -E' 
    require "syscall.ph"; 
    my $ret = syscall(&SYS_mount, "/proc", "/path/to/my/mount/point", 0, 0, 0); 
    say $ret; 
' 
Modification of a read-only value attempted at -e line 3. 

$ perl -E' 
    require "syscall.ph"; 
    my $ret = syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0); 
    say $ret; 
' 
-1 

$ strace perl -e' 
    require "syscall.ph"; 
    syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0); 
' 2>&1 | grep mount 
mount("/proc", "/path/to/my/mount/point", NULL, 0, NULL) = -1 ENOENT (No such file or directory) 
+0

你的先生/女士刚让我很快乐!我现在看到'syscall'的文档说“你不能使用字符串字面值(或其他只读字符串)作为参数”......我很傻,我应该有RTFM ......不过,既然你刚刚救了我很多头痛,我希望你有很多upvotes :) – josch

+0

Doh!还没有读过这个!稍微改进我的答案。 – ikegami