首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C程序中调用Linux重启函数会导致程序在磁盘上创建的文件丢失

问在C程序中调用Linux重启函数会导致程序在磁盘上创建的文件丢失
EN

Stack Overflow用户
提问于 2012-05-14 22:56:46
回答 4查看 9.7K关注 0票数 7

我已经开发了一个C程序(Linux),这个程序创建一个新的文件并写入,之后它重启PC。

重新启动后,我丢失了程序创建的文件。当我停用重启功能时,我的程序创建的文件仍然存在。

在Linux上可以看到这种行为:- OpenWrt (Backfire 10.03) on VirtualBox (文件系统ext2) -Linux (Ubuntu) (文件系统ext4)

你对这种行为有什么解释吗?我该如何纠正它?

代码语言:javascript
复制
#include <stdio.h>
#include <sys/reboot.h>

int main ()
{
    FILE    *pFile;
    char    mybuffer[80];

    pFile = fopen ("/home/user/Desktop/example.txt","w");
    if (pFile == NULL) perror ("Error opening file");
    else
    {
        fputs ("test",pFile);
        fclose (pFile);
    }
    rename("/home/user/Desktop/example.txt","/home/user/Desktop/example123.txt");
    reboot(RB_AUTOBOOT);
    return 0;
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-05-14 23:10:15

fclose的手册页上写着:

注意,fclose()只刷新C库提供的用户空间缓冲区。为了确保数据以物理方式存储在磁盘上,还必须刷新内核缓冲区,例如,使用sync(2)或fsync(2)。

这意味着您需要在关闭文件描述符之前调用fsync。

票数 7
EN

Stack Overflow用户

发布于 2014-08-18 17:56:01

直接的问题是,在重新启动之前没有同步文件。实际的问题是,您直接调用reboot系统调用,而不考虑系统上还发生了什么。您所做的非常类似于简单地按下HW reset按钮;您只是给内核一个机会来做一点清理,但然后一切都会以艰难的方式被杀死。这绝对是最终破坏文件系统和文件结构的一种方式。不要这样做!

相反,您应该要求init系统执行gracefull重新引导。调用reboot系统调用需要特权访问。因此,您也可以要求init系统重新启动。在大多数系统上,都有一个符号链接/sbin/reboot,它指向通过该符号链接调用时将启动正常重启的程序。因此,我建议您用(注意execlp中"/sbin/reboot"的双重规范-这一点很重要)替换您的脏reboot(RB_AUTOBOOT)。

代码语言:javascript
复制
pid_t reboot_pid;
if( 0 == (reboot_pid = fork()) ) {
    execlp("/sbin/reboot", "/sbin/reboot", NULL);
    exit(1); /* never reached if execlp succeeds. */
}
if( -1 == reboot_pid ) {
    /* fork error... deal with it somehow */
}
int reboot_status;
waitpid(reboot_pid, &reboot_status, 0);
if( !WIFEXITED(reboot_status) ) {
    /* reboot process did not exit sanely... deal with it somehow */
}
if( 0 != WIFEXITSTATUS(reboot_status) ) {
    /* reboot process exited with error;
     * most likely the user lacks the required privileges */
}
else {
    fputs("reboot call sucessfull -- system is about to shutdown.");
    /* The init system is now shutting down the system. It will signals all
     * programs to terminate by sending SIGTERM, followed by SIGKILL to
     * programs that didn't terminate gracefully. */
}

这样做,系统可以优雅地关闭,以干净的方式终止所有运行的程序,并在重新启动之前卸载所有文件系统,从而确保文件系统和数据的完整性。

请注意,如果您希望您的程序不具有root访问权限,那么您必须跳过一些障碍;在安装了systemd的系统上,您可以通过D-Bus发送一个重启请求。但是,如果执行该命令的用户没有重新启动权限,则该命令将会失败。

票数 7
EN

Stack Overflow用户

发布于 2012-05-14 23:20:22

我认为这里最重要的事情是重启永远不会回来,所以你的程序永远不会正常退出。

在正常情况下(例如,程序在调用fclose之后退出甚至崩溃),在您的file *下的文件描述符将被关闭,并且它们的内核缓冲区将被刷新。

然而,在这种情况下,由于reboot再也没有返回,我怀疑内核缓冲区没有以通常的方式得到清理,因此不会因此而将内容写入磁盘。

一个fsync调用可能会解决这个问题。如果您想要变得偏执,可以执行fsync,然后使用fileno()获取文件描述符,并使用sync()确保刷新缓冲区。此时,在进程地址空间中应该不会留下任何文件,并且调用重新启动应该不会引起更多的问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10585812

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档