/*
 * DF-2628 link loop: hammer link(payload, lnk) forever; unlink on
 * success; after every failure stat(payload) and report any nlink rise
 * (link failed but link count inflated = the bug).
 *
 * usage: linkloop <dir>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdlib.h>

static void
bye(int sig __unused)
{
	_exit(0);
}

int
main(int argc, char **argv)
{
	char payload[512], lnk[512];
	long base = -1, best = -1, attempts = 0, fails = 0;
	int hits = 0;
	time_t t0 = time(NULL);
	struct stat st;

	if (argc < 2) { fprintf(stderr, "usage: %s <dir> [seconds]\n", argv[0]); return 64; }
	if (argc >= 3) {
		signal(SIGALRM, bye);
		alarm(atoi(argv[2]));
	}
	snprintf(payload, sizeof(payload), "%s/payload", argv[1]);
	snprintf(lnk, sizeof(lnk), "%s/lnk", argv[1]);
	if (stat(payload, &st) < 0) { perror(payload); return 1; }
	base = st.st_nlink;
	setvbuf(stdout, NULL, _IONBF, 0);
	printf("linkloop uid=%d payload nlink=%ld\n", getuid(), base);

	for (;;) {
		int r = link(payload, lnk);
		++attempts;
		if (r == 0) {
			unlink(lnk);
			continue;
		}
		++fails;
		if (stat(payload, &st) == 0 && st.st_nlink > base &&
		    st.st_nlink > best) {
			best = st.st_nlink;
			++hits;
			printf("[%lds] HIT: link errno=%d but nlink %ld -> %ld "
			    "(inflation +%ld)\n", (long)(time(NULL) - t0),
			    errno, base, best, best - base);
		}
	}
	return 0;
}
