在应用程序退出之前删除所有文件

时间:2012-02-09 11:06:29

标签: c linux

我正在研究一些代码,它是工具的后端。此工具在固定目录中创建其所有输出。现在假设客户端想要杀死其所有应用程序,那么应该删除所有文件。所以我使用系统命令(rm -rf)来删除目录,但是没有删除打开的文件,因此也不会删除该目录。我怎么能聪明地做到这一点?

一个选项似乎是使用一个表来维护所有打开的文件,并在对目录触发rm -rf之前将它们全部关闭。但是,这可能会降低整个应用程序的速度。

我探讨的另一个选项是使用lsof查找打开文件的列表,并在rm -rf之前将其全部关闭。

我的问题的另一个限制是我在一个进程中打开了几个不同的文件,其中一个正由另一个进程使用。使用上述方法,如果我关闭所有文件描述符并尝试删除目录,从逻辑上讲它不应该被删除,因为还有另一个进程打开了文件。

任何建议都将不胜感激。

8 个答案:

答案 0 :(得分:3)

为什么不将程序包装在脚本中?

e.g。

#!/bin/sh

mkdir <some directory>
/path/to/program <some directory to let the program know where to put stuff>
rm -fr <the same directory>

运行此而不是直接运行程序

答案 1 :(得分:1)

在* nix系统上,您可以使用掩码和signal系统调用捕获应用程序的kill信号。有关示例代码,请参阅this question

要列出打开的文件,您只需查看/proc/**PID**/fd即可。你将拥有与lsof相同的内容:

lr-x------ 1 user user 64 2012-02-09 08:40 0 -> /dev/null
l-wx------ 1 user user 64 2012-02-09 08:40 1 -> /home/user/.xsession-errors
lrwx------ 1 user user 64 2012-02-09 08:40 11 -> /etc/passwd
l-wx------ 1 user user 64 2012-02-09 08:40 2 -> /home/user/.xsession-errors
lrwx------ 1 user user 64 2012-02-09 08:40 3 -> socket:[15449]
lr-x------ 1 user user 64 2012-02-09 08:40 4 -> socket:[15450]
l-wx------ 1 user user 64 2012-02-09 08:40 5 -> pipe:[11740]
l-wx------ 1 user user 64 2012-02-09 08:40 6 -> socket:[15448]
lrwx------ 1 user user 64 2012-02-09 08:40 7 -> anon_inode:[eventfd]
lrwx------ 1 user user 64 2012-02-09 08:40 8 -> pipe:[11740]
lrwx------ 1 user user 64 2012-02-09 08:40 9 -> /dev/urandom

使用此列表,您将能够在离开之前grep感兴趣的文件并通过fd在信号处理程序中关闭它们。

答案 2 :(得分:1)

如果某个进程在目录中打开文件并且该目录位于远程磁盘上,则应该只删除整个目录。在这种情况下,删除打开的文件可能会导致重命名,以便远程系统可以维护对文件的引用。如果文件位于本地磁盘上,则维护对已删除文件的引用没有问题。

当文件打开的进程终止时,操作系统将自动关闭文件。如果没有其他进程打开任何文件,则删除目录应该没有问题(假设没有其他问题,例如文件权限)。因此,您只需要确保在删除目录之前终止打开文件的进程。

答案 3 :(得分:1)

来自'fcloseall'手册页:

#define _GNU_SOURCE
/* See feature_test_macros(7) *
/#include <stdio.h>
int fcloseall(void);

这可以假设您的应用程序使用'fopen'和朋友:)

答案 4 :(得分:1)

除了其他答案之外,如果您确定所有文件都是在已知的临时目录中创建的,并且程序正常终止(通过调用exit或从main返回)可以使用atexit注册清理函数,该函数将使用opendirreaddir来收集所有文件名并删除它们,然后rmdir目录本身。

我在gcc/melt-runtime.c文件中执行类似操作,在第10390行附近执行do_finalize_melt

您还可以向atexit注册一个调用system("rm -rf /path/to/your/dir")的函数,或者甚至可以运行一个脚本,该脚本将排队到batch系统另一个执行rm -rf的脚本或只是调用atexit(myexit_handler)

void myexit_handler(void)
{
   FILE* batchf = popen("/usr/bin/batch", "w");
   /* get some sleep to be sure our process had time to exit */
   fprintf (batchf, "/bin/sleep 5\n"); 
   fprintf (batchf, "/bin/rm -rf %s\n", yourtempdir);
   pclose (batchf);
}

我假设yourtempdir里面没有顽皮的字符(例如没有空格或引号或反斜杠......)

Linux语义是程序退出时删除已打开但已删除的文件。如果这些是NFS文件(但是在网络上放置一个临时目录是恕我直言,因为你希望它快!)然后确实有一些.nfs*文件保留在NFS服务器上(你需要一些方法来删除它们,可能是ssh)。

应用程序退出之前,您不应该尝试删除目录,但是之后退出,否则仍然打开的文件将不会被删除。

答案 5 :(得分:0)

我认为使用脚本对你的实例来说是一个好主意,而且Coren的答案是准确的。话虽这么说,我看到程序只是遍历大量的文件描述符来关闭所有这些。如果你有超过你循环的范围,它有可能出错,但如果你打算关闭所有描述符,只要它们在这个限制范围内,这样的事情不应该伤害应用程序:

for (int i = 0; i < 4096; i++) {
    close(i);
}

为了在应用程序退出之前完成此操作,您可以设置信号处理程序,如Coren所述和链接。确保在信号处理程序中使用尽可能少的信号和处理程序,即只需设置一个标志并让程序进行清理。

编辑:此外,来自StackOverflow上另一篇文章的this answer给出了两个如何执行此操作的示例(#3与Coren相似,适用于Linux),但也有一些链接到处理这些东西的实际源代码。你可能想看看它!

答案 6 :(得分:0)

tmpfile功能对您有帮助吗?这会创建一个在程序退出时自动删除的临时文件(我认为abort可能会覆盖它)。

如果这不起作用,请注意(至少在Linux上)可以在文件关闭之前删除它们。它们从目录列表中消失,但任何打开文件的程序仍然可以访问它。一旦所有程序关闭文件,它就会消失。在此之前,重新打开它们的唯一方法是查看/proc/<pid>/fd/<num>。这是flash插件使用的技巧,使得抓取视频流变得更加困难。

答案 7 :(得分:0)

使用getdtablesize,假设您不想关闭stdin,stdout,stderr:

for(i=3;i<getdtablesize(); i++)
     ckerr(close(i));

其中ckerr是错误检查功能。请注意,这符合旧标准:

        SVr4, 4.4BSD (the getdtablesize() function first appeared in 4.2BSD). 
    It is not specified in POSIX.1-2001; portable applications should employ
 sysconf(_SC_OPEN_MAX) instead of this call.

所以这纯粹是一个穷人的替代品....但它还没有被弃用。

考虑调用nftw()或ftw()来清理你的工作指导,你可以在回调函数中执行remove()。