Python ctypes 在Linux上调用libc中的reboot()

5 投票
2 回答
1763 浏览
提问于 2025-04-16 18:43

我正在尝试通过 ctypes 在 Python 中调用 libc 的 reboot 函数,但就是无法成功。我参考了 man 2 reboot 的页面(http://linux.die.net/man/2/reboot)。我的内核版本是 2.6.35。

下面是我在交互式 Python 提示符下尝试重启机器时的控制台日志——我到底哪里做错了?

为什么 ctypes.get_errno() 不起作用?

>>> from ctypes import CDLL, get_errno
>>> libc = CDLL('libc.so.6')
>>> libc.reboot(0xfee1dead, 537993216, 0x1234567, 0)
-1
>>> get_errno()
0
>>> libc.reboot(0xfee1dead, 537993216, 0x1234567)
-1
>>> get_errno()
0
>>> from ctypes import c_uint32
>>> libc.reboot(c_uint32(0xfee1dead), c_uint32(672274793), c_uint32(0x1234567), c_uint32(0))
-1
>>> get_errno()
0
>>> libc.reboot(c_uint32(0xfee1dead), c_uint32(672274793), c_uint32(0x1234567))
-1
>>> get_errno()
0
>>>

编辑:

根据 Nemos 的提醒——我可以让 get_errno 返回 22(无效参数)。这并不意外。我应该怎么调用 reboot()?显然我没有传递函数所期望的参数。=)

2 个回答

3

libc中的reboot()其实是一个封装,它只是对系统调用的一个简单包装,主要是用来处理cmd这个参数。所以你可以试试:

libc.reboot(0x1234567)

需要注意的是,通常你应该通过向进程ID为1的程序发送SIGINT信号来启动重启。直接告诉内核重启的话,系统中的一些后台服务就没有机会正常关闭,甚至连文件系统的缓存都不会同步到硬盘上。

4

试试这个:

>>> libc = CDLL('libc.so.6', use_errno=True)

这样应该可以让 get_errno() 正常工作。

[更新]

另外,最后一个参数是 void *。如果你是在64位系统上,那么整数0并不能正确表示NULL。你可以试试 None 或者 c_void_p(None)。不过我不太确定在这个情况下这有什么影响。

[更新 2]

显然 reboot(0x1234567) 可以解决这个问题(见评论)。

撰写回答