有时您需要卸载文件系统或分离循环设备,但这是busy
因为打开的文件描述符,可能是因为smb
服务器进程。
要强制卸载,您可以终止有问题的进程(或 try kill -SIGTERM
),但这会关闭smb
连接(即使它打开的某些文件不需要关闭)。
这里使用gdb
to call描述了一种强制进程关闭给定文件描述符的 hacky 方法close(fd)
。然而,这似乎很危险。如果关闭的描述符被回收了怎么办?该进程可能使用旧的存储描述符,但没有意识到它现在指的是完全不同的文件。
我有一个想法,但不知道它有什么样的缺陷:使用gdb
,打开/dev/null
方式O_WRONLY
(编辑:建议O_PATH
作为更好的选择的评论),然后dup2
关闭有问题的文件描述符并将其描述符重用于/dev/null
. 这样,对文件描述符的任何读取或写入都将失败。
像这样:
sudo gdb -p 234532
(gdb) set $dummy_fd = open("/dev/null", 0x200000) // O_PATH
(gdb) p dup2($dummy_fd, offending_fd)
(gdb) p close($dummy_fd)
(gdb) detach
(gdb) quit
会出什么问题?
摆弄一个流程
gdb
几乎从来都不是安全的,但如果有一些紧急情况并且流程需要保持开放并且所涉及的所有风险和代码都被理解,则可能是必要的。大多数情况下,我会简单地终止该进程,尽管某些情况可能会有所不同,并且可能取决于环境、谁拥有相关系统和所涉及的进程、该进程正在做什么、是否有关于“可以杀死它”或“不,先联系某某”等。这些细节可能需要在尘埃落定后的事后会议上制定。如果有计划的迁移,最好提前检查是否有任何进程打开了有问题的文件描述符,以便可以在非紧急设置中处理这些问题(cron 作业或仅在迁移时的凌晨运行的其他计划任务如果您只在白天检查,可能很容易错过)。
只写与读取与读写
您重新打开文件描述符的想法
O_WRONLY
是有问题的,因为并非所有文件描述符都是只写的。John Viega 和 Matt Messier 在“Secure Programming Cookbook for C and C++”一书中采用了更细致入微的方法,并以不同于标准输出和标准错误的方式处理标准输入(第 25 页,“安全管理文件描述符”):在这种
gdb
情况下,需要检查描述符(或FILE *
句柄)是只读的、读写的还是只写的,并在/dev/null
. 如果不是这样,如果进程试图从中读取,现在只写的曾经只读句柄将导致不必要的错误。会出什么问题?
当它的文件描述符(可能还有
FILE *
句柄)在幕后被摆弄时,进程的行为究竟如何取决于进程,并且如果该描述符永远不会被使用,则从“没什么大不了”到现在有一个“噩梦模式”由于未刷新的数据、没有正确关闭文件的指示器或其他一些未预料到的问题,导致文件损坏。对于
FILE *
句柄,fflush(3)
在关闭句柄之前添加调用可能会有所帮助,或者可能导致双缓冲或其他一些问题;这是在gdb
不确切知道源代码的作用和期望的情况下进行随机调用的几个危险之一。fd
软件还可能在描述符或句柄之上构建额外的复杂层,FILE *
这些也可能需要处理。猴子修补代码很容易变成猴子扳手。概括
向进程发送标准终止信号应该给它一个正确关闭资源的机会,就像系统正常关闭时一样。摆弄一个过程
gdb
可能不会正确地结束事情,并且可能会使情况变得更糟。如果将描述符复制到
/dev/null
,则任何写入都不会失败,而是成功,并且读取将成功并返回 0 (eof)。这可能是也可能不是您想要的。
在 linux 上,您还可以打开一个带有 flags = 3 (
O_WRONLY|O_RDWR
akaO_NOACCESS
) 的文件,这将导致任何读取或写入失败EBADF
。该文件仅可用于 ioctls - 这带来了其他答案和评论中未提及的危险:读取和写入并不是对文件描述符进行的唯一操作。(关于
lseek
或ftruncate
?)。更新:
我发现了比无证更好的东西
O_WRONLY|O_RDWR
:O_PATH = 010000000 / 0x200000
。根据 open(2) 联机帮助页: