/* This simple program is used to illustrate that the OS does not free up
 * the disk space used by a file immediately after a call to unlink(2),
 * but only after the last process with an open handle has terminated.
 *
 * Run like this:
 *
 * $ cc -Wall wait-unlink.c
 * $ ./a.out
 * $ df .
 */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char **argv) {

	/* setup: create a 500M file */
	printf("Creating a 500M file...\n");
	if (system("dd if=/dev/zero of=foo bs=1024k count=2000 2> /dev/null") != 0) {
		perror("unable to dd a new file");
		exit(EXIT_FAILURE);
	}

	if (system("df -h .") != 0) {
		perror("unable to run df(1)");
		exit(EXIT_FAILURE);
	}

	printf("\nLinking 'bar' to 'foo'...\n");
	if (link("foo", "bar") == -1) {
		perror("unable to create a second hard link");
		exit(EXIT_FAILURE);
	}

	if (system("ls -li foo bar") != 0) {
		perror("unable to run ls(1)");
		exit(EXIT_FAILURE);
	}

	if (system("df -h .") != 0) {
		perror("unable to run df(1)");
		exit(EXIT_FAILURE);
	}

	if (open("foo", O_RDWR) < 0) {
		perror("can't open file");
		exit(EXIT_FAILURE);
	}

	if (unlink("foo") < 0) {
		perror("error unlinking");
		exit(EXIT_FAILURE);
	}

	printf("\nOk, foo unlinked.  Disk space not free'd since 'bar' still exists...\n");
	system("ls -li foo bar");

	if (system("df -h .") != 0) {
		perror("unable to run df(1)");
		exit(EXIT_FAILURE);
	}

	sleep(3);

	printf("\nOk, now unlinking 'bar'...\n");
	if (unlink("bar") < 0) {
		perror("error unlinking");
		exit(EXIT_FAILURE);
	}

	printf("\nOk, bar unlinked.  Disk space not free'd since I still have a file handle open...\n");
	printf("\nRunning 'ls -li foo bar':\n");
	system("ls -li foo bar");

	if (system("df -h .") != 0) {
		perror("unable to run df(1)");
		exit(EXIT_FAILURE);
	}

	sleep(3);
	printf("\n...and done.  Disk space is freed now.\n");
	printf("Run 'df .' to verify.\n");
	exit(EXIT_SUCCESS);
}
