从Perl执行挂载系统调用

5
如何从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);

但是,这种选项的分割无法起作用。我需要在单个mount系统调用中使用MS_BINDMS_REC | MS_PRIVATE才能在非特权未共享的挂载命名空间中工作。
那么,在Perl中如何进行初始系统调用而不会出现关于试图修改只读值的错误消息?
编辑: 幸运的是,Ikegami很快指出了在尝试使用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系统调用,因为两者都可以很好地工作 :)。

2个回答

8

syscall函数拒绝传递指向常量的字符串缓冲区的指针,因为它不知道参数是char *还是const char *

您不能将字符串字面量(或其他只读字符串)用作syscall的参数,因为Perl必须假定任何字符串指针都可能被写入

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

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)

您先生/女士刚刚让我开心了一整天!我现在明白了syscall文档中所说的“您不能将字符串字面值(或其他只读字符串)用作参数”...我真是太傻了,我应该好好阅读文档...尽管如此,既然您刚刚帮我避免了很多麻烦,我祝愿您获得更多的赞 :) - josch

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接