I have developped a C program (Linux), this program create a new file and write into, after that it reboots the PC.
After reboot, I have lost the file created by my program. When I deactivate reboot function, the file created by my program is still present.
This behaviour is seen with Linux: - OpenWrt (Backfire 10.03) on VirtualBox (filesystem ext2) - Linux (Ubuntu) (filesystem ext4)
Have you an explication for this behavior and how can I fix it?
#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;
}
The man page for fclose says:
Note that fclose() only flushes the user space buffers provided by the C library. To ensure that the data is physically stored on disk the kernel buffers must be flushed too, for example, with sync(2) or fsync(2).
Which means that you need to call fsync before closing the file descriptor.
The immediate problem is, that you don't sync the file before doing the reboot. The actual problem is, that you call the reboot
syscall directly, without regard for what else is happening on the system. What you do is very similar to simply pressing the HW reset button; you just give the kernel the chance to do a little bit of cleanup, but then everything is killed the hard way. This is a dead sure way to eventually corrupt filesystems and file structures. Don't do this!.
Instead you should ask the init system to perform a gracefull reboot. Calling the reboot
syscall requires privileged access. So you can just ask the init system to reboot as well. On most systems there's a symlink /sbin/reboot
that points to the program that will initiate a sane reboot if called through that symlink. Hence I recommend you replace your dirty reboot(RB_AUTOBOOT)
with (note the double specification of "/sbin/reboot"
in execlp – this is important).
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. */
}
Doing it that way the system can shut down gracefully, terminate all programs running in a clean way and unmount all filesystems before doing the reboot, thereby keeing filesystem and data integrity.
Note that if you expect your program not to have root access, then you'll have to jump some hoops; on systems with systemd you can send a reboot request by D-Bus. But except it to fail, if the user executing the command does not have reboot privileges.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With